Repository navigation
0.8.0
NnFileKit 0.8.0
This release adds copying, byte-level file comparison, and helpers for nested and absolute directory paths. It also makes named: parameters accept only a single path component. Code that passed nested paths through named:, code that implements Directory or FileSystem, and tests that use MockDirectory may need changes.
Breaking changes
New protocol requirements
Directory now requires copy(to:overwrite:), copyFile(named:to:overwrite:), and fileContentsEqual(named:in:). FileSystem now requires createDirectory(at:).
Who is affected: projects with their own types that conform to Directory or FileSystem. DefaultDirectory, DefaultFileSystem, and the NnFileTesting mocks already implement these methods.
Action: add the four methods to your conforming types.
named: parameters accept a single path component
Previously: a name containing /, such as subdirectory(named: "assets/images"), was appended to the directory's path, so the method reached the nested location.
Now: a name containing / makes throwing methods throw FileSystemError.invalidName, and makes containsFile(named:) and containsSubdirectory(named:) return false.
Action: switch nested lookups and creation to the relative-path methods:
// Before
let images = try directory.subdirectory(named: "assets/images")
// After
let images = try directory.subdirectory(atRelativePath: "assets/images")
let created = try directory.createSubdirectory(atRelativePath: "assets/images")For file operations such as readFile(named:) or createFile(named:contents:) on nested files, resolve the containing directory first, then pass only the file name.
New FileSystemError.invalidName case
FileSystemError has a new case. A switch over FileSystemError without a default clause will no longer compile.
Action: handle .invalidName(String) or add a default clause.
MockDirectory.createSubdirectory(named:) throws for existing names
Previously: the mock returned the existing subdirectory. Now: it throws, the same way DefaultDirectory does.
Action: tests that rely on get-or-create behavior should call createSubfolderIfNeeded(named:) instead.
Copying and comparing
copy(to:overwrite:)copies a directory, including nested contents and symlinks, into a parent directory under its own name. It returns the copy.copyFile(named:to:overwrite:)copies one file into another directory under the same name. It returns the new file's path.- In
DefaultDirectory, both methods throw if the destination already exists andoverwriteisfalse. Withoverwrite: true, the existing destination is deleted before the copy starts. That step is not atomic: if the copy fails afterward, the original destination is already gone. fileContentsEqual(named:in:)checks whether a file has the same bytes as the file with that name in another directory. Binary files work. It returnsfalseif the other directory doesn't have the file, and throwsFileSystemError.fileNotFoundif the receiving directory doesn't.
Nested and absolute paths
FileSystem.createDirectory(at:)returns the directory at an absolute path. If the directory or any parent is missing, it creates them first.Directory.subdirectory(atRelativePath:)opens a nested subdirectory.createSubdirectory(atRelativePath:)does the same but creates any missing folders along the way. Both throwFileSystemError.invalidNamefor a path that starts with/, and return the receiving directory when the path is empty.
Testing support
MockDirectory records directory copies in copiedToParents and file copies in copiedFiles, including the overwrite flag. Tests can assert on both. The mock doesn't enforce overwrite. When the destination is a MockDirectory, a successful copy also adds the copied item to it.
Full changelog: 0.7.0...0.8.0