Files
swiftpm-pathkit/Sources/Path+FileManager.swift
2019-01-19 14:36:27 -05:00

175 lines
5.5 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Foundation
public extension Path {
/**
Copies a file.
- Note: `throws` if `to` is a directory.
- Parameter to: Destination filename.
- Parameter overwrite: If true overwrites any file that already exists at `to`.
- Returns: `to` to allow chaining
- SeeAlso: copy(into:overwrite:)
*/
@discardableResult
public func copy(to: Path, overwrite: Bool = false) throws -> Path {
if overwrite, to.exists {
try FileManager.default.removeItem(at: to.url)
}
try FileManager.default.copyItem(atPath: string, toPath: to.string)
return to
}
/**
Copies a file into a directory
If the destination does not exist, this function creates the directory first.
- Note: `throws` if `into` is a file.
- Parameter into: Destination directory
- Parameter overwrite: If true overwrites any file that already exists at `into`.
- Returns: The `Path` of the newly copied file.
- SeeAlso: copy(into:overwrite:)
*/
@discardableResult
public func copy(into: Path, overwrite: Bool = false) throws -> Path {
if !into.exists {
try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true)
} else if overwrite, !into.isDirectory {
try into.delete()
}
let rv = into/basename()
try FileManager.default.copyItem(at: url, to: rv.url)
return rv
}
/**
Moves a file.
- Note: `throws` if `to` is a directory.
- Parameter to: Destination filename.
- Parameter overwrite: If true overwrites any file that already exists at `to`.
- Returns: `to` to allow chaining
- SeeAlso: move(into:overwrite:)
*/
@discardableResult
public func move(to: Path, overwrite: Bool = false) throws -> Path {
if overwrite, to.exists {
try FileManager.default.removeItem(at: to.url)
}
try FileManager.default.moveItem(at: url, to: to.url)
return to
}
/**
Moves a file into a directory
If the destination does not exist, this function creates the directory first.
- Note: `throws` if `into` is a file.
- Parameter into: Destination directory
- Parameter overwrite: If true overwrites any file that already exists at `into`.
- Returns: The `Path` of destination filename.
- SeeAlso: move(into:overwrite:)
*/
@discardableResult
public func move(into: Path) throws -> Path {
if !into.exists {
try into.mkpath()
} else if !into.isDirectory {
throw CocoaError.error(.fileWriteFileExists)
}
let rv = into/basename()
try FileManager.default.moveItem(at: url, to: rv.url)
return rv
}
/// Deletes the path, recursively if a directory.
@inlinable
public func delete() throws {
try FileManager.default.removeItem(at: url)
}
/**
Creates an empty file at this path.
- Returns: `self` to allow chaining.
*/
@inlinable
@discardableResult
func touch() throws -> Path {
return try "".write(to: self)
}
/// Helper due to Linux Swift being incomplete.
private func _foo(go: () throws -> Void) throws {
#if !os(Linux)
do {
try go()
} catch CocoaError.Code.fileWriteFileExists {
// noop
}
#else
do {
try go()
} catch {
let error = error as NSError
guard error.domain == NSCocoaErrorDomain, error.code == CocoaError.Code.fileWriteFileExists.rawValue else {
throw error
}
}
#endif
}
/**
Creates the directory at this path.
- Note: Does not create any intermediary directories.
- Returns: `self` to allow chaining.
*/
@discardableResult
public func mkdir() throws -> Path {
try _foo {
try FileManager.default.createDirectory(at: self.url, withIntermediateDirectories: false, attributes: nil)
}
return self
}
/**
Creates the directory at this path.
- Note: Creates any intermediary directories, if required.
- Returns: `self` to allow chaining.
*/
@discardableResult
public func mkpath() throws -> Path {
try _foo {
try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
}
return self
}
/**
Replaces the contents of the file at this path with the provided string.
- Note: If file doesnt exist, creates file
- Note: If file is not writable, makes writable first, resetting permissions after the write
- Parameter contents: The string that will become the contents of this file.
- Parameter atomically: If `true` the operation will be performed atomically.
- Parameter encoding: The string encoding to use.
- Returns: `self` to allow chaining.
*/
@discardableResult
public func replaceContents(with contents: String, atomically: Bool = false, encoding: String.Encoding = .utf8) throws -> Path {
let resetPerms: Int?
if exists, !isWritable {
resetPerms = try FileManager.default.attributesOfItem(atPath: string)[.posixPermissions] as? Int
let perms = resetPerms ?? 0o777
try chmod(perms | 0o200)
} else {
resetPerms = nil
}
defer {
_ = try? resetPerms.map(self.chmod)
}
try contents.write(to: self)
return self
}
}