copy

A Go library for recursively copying directories and files, with fine-grained control over symlinks, permissions, and concurrency.

Library
Go
vv1.14.1
772stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
44/100Fair
Development Activity0
Maintenance20
Community68
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
76/100Good
Architecture82
Code Quality78
Innovation80
Learning Curve65

copy is a small Go library that recursively copies directories and files, filling a gap left by the standard library’s os and io packages, which offer no built-in directory-copy primitive. A single Copy(src, dest) call walks the source tree and replicates it at the destination, correctly handling regular files, subdirectories, symlinks, and, optionally, special files like named pipes and devices.

Beyond the basic case, an Options struct lets callers customize nearly every step of the walk: how symlinks are resolved (shallow copy, deep dereference, or skip), what happens when a destination directory already exists (merge, replace, or leave untouched), which files to skip via a predicate, how file permissions are set or preserved, and whether directory copying should run concurrently across a worker pool backed by a weighted semaphore. It also supports copying from any fs.FS, including embed.FS, making it useful for extracting assets bundled into a Go binary.

What You Get

  • A single Copy(src, dest, opts...) API that works for both single files and entire directory trees, with no other setup required.
  • Configurable symlink handling — copy the link itself (Shallow), copy the linked file’s contents (Deep), or skip it entirely.
  • Options for directory-exists conflicts — Merge, Replace, or Untouchable — so integrators can decide destination behavior precisely.
  • Concurrent directory copying via NumOfWorkers and a semaphore-backed worker pool for faster copies of large trees.
  • Support for copying from any fs.FS (including Go’s embed.FS), so bundled or in-memory filesystems work the same as the OS filesystem.

Common Use Cases

  • Scaffolding project templates — copying a boilerplate directory tree into a new project location during a CLI init command.
  • Test fixture setup — duplicating a golden test-data directory into a temp path before each test run so tests don’t mutate shared fixtures.
  • Backup and snapshot tooling — recursively copying a directory before performing a destructive operation, to allow rollback.
  • Bundling embedded assets — copying files from an embed.FS into a real filesystem path at runtime, e.g. extracting default config or templates shipped inside a binary.

Under The Hood

Architecture The package is a single flat copy package with no internal layering — one file per concern (copy.go, options.go, permission_control.go, plus platform-specific files for preserving timestamps and ownership). Execution starts at Copy() in copy.go, which normalizes an Options struct via assureOptions, then dispatches through a single switchboard function that branches on file mode — symlink, directory, named pipe, or regular file — recursing through dcopySequential/dcopyConcurrent for directories. Cross-cutting concerns such as permission control, ownership/time preservation, and symlink resolution are implemented as small, replaceable strategy functions (PermissionControlFunc, OnSymlink, OnDirExists, OnError) injected via Options rather than hardcoded, a lightweight dependency-injection style. Platform differences are isolated behind build-tag file suffixes. Because switchboard is the sole recursive dispatch point, any change to its file-type handling affects every caller uniformly.

Tech Stack A pure Go 1.18 module with only two runtime dependencies: golang.org/x/sync (semaphore and errgroup, used for concurrent directory copying) and golang.org/x/sys (platform syscalls for ownership/time preservation), plus otiai10/mint as a test-only BDD-style assertion library. There is no build tooling beyond go build/go test; CI runs the suite across multiple environments — native GitHub Actions, Docker, Vagrant, GopherJS transpilation, and WASM — to validate cross-platform and cross-runtime behavior for a package with no database or web-framework surface of its own.

Code Quality Extensive test coverage spans symlink handling, permission strategies, directory-exists policies, and platform-specific timestamp preservation, organized into top-level Test functions with nested When sub-tests using the otiai10/mint assertion library rather than raw stdlib assertions. Error handling is explicit and typed, propagated through named return values with defer-based capture helpers (fclose, chmod) rather than swallowed, and an OnError hook lets callers intentionally suppress specific errors. Naming is consistent and idiomatic Go (dcopy/fcopy/lcopy/pcopy verb prefixes). No linter configuration is checked into the repo, but CodeQL analysis and Go Report Card badges, combined with per-OS and per-runtime CI, provide comparable coverage.

API Design The public surface is minimal and ergonomic — one function, Copy(src, dest string, opts ...Options) error, covers both the zero-config case and the fully customized case via a single optional variadic Options struct, avoiding a separate configured-call variant. Every option is independently optional, with assureOptions backfilling anything left unset, so callers can override just one behavior without reconstructing the whole struct. Named enum types (SymlinkAction, DirExistsAction) make call sites self-documenting compared to boolean flags, and support for stdlib fs.FS (including embed.FS) integrates cleanly with idiomatic modern Go. One minor rough edge: a deprecated AddPermission field remains alongside the newer PermissionControlFunc for backwards compatibility, requiring readers to know one supersedes the other.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search