Skip to content

Instantly share code, notes, and snippets.

@pepicrft
Last active January 12, 2026 11:53
Show Gist options
  • Select an option

  • Save pepicrft/9ba19c9745903333d8a7f50eab0aa7fb to your computer and use it in GitHub Desktop.

Select an option

Save pepicrft/9ba19c9745903333d8a7f50eab0aa7fb to your computer and use it in GitHub Desktop.
This gist is a summary of the file-system APIs that Tuist makes usage of

Tuist file-system API usage

This document summarizes the file-system APIs Tuist uses today. The project relies on the tuist/FileSystem package (see Package.swift, product FileSystem, version 0.11.x) with its FileSysteming protocol and default FileSystem implementation. Tests use FileSystemTesting, and some code handles _NIOFileSystem.FileSystemError.

Core abstractions

  • FileSysteming: async interface for path operations; default instance is FileSystem().
  • Paths: AbsolutePath / RelativePath (from the Path package) are passed to all APIs.
  • Testing utilities: FileSystem.temporaryTestDirectory, FileSystemTesting traits for temporary dirs and assertions.
  • Legacy helpers: a few spots still use FileHandler.shared (pre-FileSystem utility) for sync operations like isFolder, contentsOfDirectory, readTextFile, touch, createFolder, and file-size checks; _NIOFileSystem.FileSystemError is also surfaced in manifest cache logic.

Legacy predecessor: FileHandler

  • Location: cli/Sources/TuistSupport/Utils/FileHandler.swift; globally accessible as FileHandler.shared implementing FileHandling.
  • Characteristics: synchronous API (no async/await); provides path operations, directory creation/removal, text/binary read/write, plist/JSON helpers, files() traversal, zip/unzip helpers (via FileArchiver/FileUnarchiver), and currentPath.
  • Current usage: still referenced across loaders (template git loader, recursive manifest loader), generators (workspace writer, target builder), automation, server services, CLI services, scaffolding, and tests. Many mappers/lints still call isFolder/contentsOfDirectory on FileHandler.
  • Migration note: any replacement must either:
    1. keep a compatibility adapter for FileHandling to avoid touching large call sites immediately, or
    2. provide parity for synchronous APIs, or convert those call sites to async FileSysteming equivalents plus executors/actors for thread safety.

Operations used across the codebase

Existence and metadata

  • exists(path, isDirectory:) — ubiquitous guards before reads/writes; used in loaders, linters, generators, automation, server services.
  • fileSizeInBytes(at:) — used when uploading artifacts (server upload services).
  • resolveSymbolicLink(_:) — used by content hashing when traversing directories.
  • isGlobPattern(_:) — used in manifest mappers to decide when to expand globs.

Directory and file lifecycle

  • makeDirectory(at:) — creating cache directories, derived data folders, scaffold outputs, test fixtures, and module outputs.
  • remove(_:) — cleaning cached manifests, wiping shared schemes before writing, deleting temp directories.
  • copy(from:to:) — duplicating fixtures, copying build outputs/artifacts, moving Package.resolved files.
  • createSymbolicLink(from:to:) — syncing Package.resolved between workspace and root.
  • touch(_:) — creating empty files in tests and resource setups.
  • runInTemporaryDirectory(prefix:, body:) — temporary working directories for test setup, xcresult parsing, device discovery.

Reading

  • readFile(at:) — binary reads (e.g., workspace state, previews upload icons).
  • readTextFile(at:) — plain-text reads for settings, metadata stores.
  • readJSONFile(at:, decoder:) — decoding JSON content (e.g., xcresult manifests, metadata stores).
  • readPlistFile(at:, decoder:) — decoding plist content (xcactivity logs, xcresults).

Writing

  • writeText(_:at:, options:) — writing configs, metadata, generated module maps, test plans.
  • writeAsJSON(_:at:, options:) — storing metadata (recent paths, CAS metadata).

Globbing and traversal

  • glob(directory: include:, excluding:) — locating manifests, resources, xcodeproj/xcworkspace, headers, swift modules, IPA/app bundles. Used heavily in loaders and generators.
  • throwingGlob(directory: include:, excluding:) — similar to glob with stricter error handling in manifest mappers.

High-traffic areas

  • Loaders & mappers (TuistLoader): manifest discovery, resource resolution, SwiftPM graph loading, package info mapping.
  • Generators (TuistGenerator): scheme writing, derived data cleanup, scaffolding, SPM interop, linting.
  • Automation (TuistAutomation): locating workspaces, app bundles, build outputs.
  • Caching & hashing (TuistCache, TuistHasher, TuistCore): directory traversal, symlink resolution, file size checks.
  • Server services (TuistServer): multipart uploads, preview/icon uploads, credential stores.
  • CLI utilities (TuistSupport, TuistTesting, tuistfixturegenerator): archiving/unarchiving, recent path storage, fixture generation.

Notes for replacement evaluation

  • APIs are async/await-friendly and path-type-safe (AbsolutePath/RelativePath), so replacements should preserve async semantics and path safety.
  • Globbing is a first-class feature; patterns include recursive ** and optional exclusion lists.
  • Temporary directory helpers (runInTemporaryDirectory, temporaryTestDirectory) are used in both production code and tests.
  • Symbolic link support is required (creating and resolving) for SwiftPM interoperability.
  • Error handling currently expects FileSystemError and _NIOFileSystem.FileSystemError in some paths; a replacement should map errors cleanly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment