From 7a91cb250f9e782b7e7f66287e15a71b81c31eee Mon Sep 17 00:00:00 2001 From: Alex Tran Qui Date: Thu, 31 Mar 2016 00:46:47 +0200 Subject: [PATCH 1/5] Added support for swift 3.0 (DEVELOPMENT-SNAPSHOT-2016-03-24-a) --- Sources/PathKit.swift | 1271 +++++++++++++++++++++++------------------ 1 file changed, 715 insertions(+), 556 deletions(-) diff --git a/Sources/PathKit.swift b/Sources/PathKit.swift index 9632986..7bcf7ae 100644 --- a/Sources/PathKit.swift +++ b/Sources/PathKit.swift @@ -1,405 +1,513 @@ // PathKit - Effortless path operations #if os(Linux) -import Glibc - + import Glibc + let system_glob = Glibc.glob #else -import Darwin - + import Darwin + let system_glob = Darwin.glob #endif import Foundation -/// Represents a filesystem path. -public struct Path { - /// The character used by the OS to separate two path elements - public static let separator = "/" - - /// The underlying string representation - internal var path: String - - internal static var fileManager = NSFileManager.defaultManager() - - // MARK: Init - - public init() { - self.path = "" - } +#if !swift(>=3.0) + typealias Collection = CollectionType + typealias Sequence = SequenceType + typealias IteratorProtocol = GeneratorType + + +#endif - /// Create a Path from a given String - public init(_ path: String) { - self.path = path - } - /// Create a Path by joining multiple path components together - public init(components: S) { +/// Represents a filesystem path. +public struct Path { + /// The character used by the OS to separate two path elements + public static let separator = "/" + + /// The underlying string representation + internal var path: String + + internal static var fileManager = NSFileManager.defaultManager() + + // MARK: Init + + public init() { + self.path = "" + } + + /// Create a Path from a given String + public init(_ path: String) { + self.path = path + } + + /// Create a Path by joining multiple path components together + #if !swift(>=3.0) + public init(components: S) { + if components.isEmpty { + path = "." + } else if components.first == Path.separator && components.count > 1 { + let p = components.joinWithSeparator(Path.separator) + #if os(Linux) + let index = p.startIndex.distanceTo(p.startIndex.successor()) + path = NSString(string: p).substringFromIndex(index) + #else + path = p.substringFromIndex(p.startIndex.successor()) + #endif + + } else { + path = components.joinWithSeparator(Path.separator) + } + } + #else + public init(components: S) { if components.isEmpty { - path = "." + path = "." } else if components.first == Path.separator && components.count > 1 { - let p = components.joinWithSeparator(Path.separator) -#if os(Linux) - let index = p.startIndex.distanceTo(p.startIndex.successor()) - path = NSString(string: p).substringFromIndex(index) -#else - path = p.substringFromIndex(p.startIndex.successor()) -#endif - + let p = components.joined(separator: Path.separator) + #if os(Linux) + let index = p.startIndex.distanceTo(p.startIndex.successor()) + path = NSString(string: p).substringFromIndex(index) + #else + path = p.substring(from: p.startIndex.successor()) + #endif + } else { - path = components.joinWithSeparator(Path.separator) + path = components.joined(separator: Path.separator) + } } - } + + #endif } - // MARK: StringLiteralConvertible extension Path : StringLiteralConvertible { - public typealias ExtendedGraphemeClusterLiteralType = StringLiteralType - public typealias UnicodeScalarLiteralType = StringLiteralType - - public init(extendedGraphemeClusterLiteral path: StringLiteralType) { - self.init(stringLiteral: path) - } - - public init(unicodeScalarLiteral path: StringLiteralType) { - self.init(stringLiteral: path) - } - - public init(stringLiteral value: StringLiteralType) { - self.path = value - } + public typealias ExtendedGraphemeClusterLiteralType = StringLiteralType + public typealias UnicodeScalarLiteralType = StringLiteralType + + public init(extendedGraphemeClusterLiteral path: StringLiteralType) { + self.init(stringLiteral: path) + } + + public init(unicodeScalarLiteral path: StringLiteralType) { + self.init(stringLiteral: path) + } + + public init(stringLiteral value: StringLiteralType) { + self.path = value + } } // MARK: CustomStringConvertible extension Path : CustomStringConvertible { - public var description: String { - return self.path - } + public var description: String { + return self.path + } } // MARK: Hashable extension Path : Hashable { - public var hashValue: Int { - return path.hashValue - } + public var hashValue: Int { + return path.hashValue + } } // MARK: Path Info extension Path { - /// Test whether a path is absolute. - /// - /// - Returns: `true` iff the path begings with a slash - /// - public var isAbsolute: Bool { - return path.hasPrefix(Path.separator) - } - - /// Test whether a path is relative. - /// - /// - Returns: `true` iff a path is relative (not absolute) - /// - public var isRelative: Bool { - return !isAbsolute - } - - /// Concatenates relative paths to the current directory and derives the normalized path - /// - /// - Returns: the absolute path in the actual filesystem - /// - public func absolute() -> Path { - if isAbsolute { - return normalize() - } - - return (Path.current + self).normalize() - } - - /// Normalizes the path, this cleans up redundant ".." and ".", double slashes - /// and resolves "~". - /// - /// - Returns: a new path made by removing extraneous path components from the underlying String - /// representation. - /// - public func normalize() -> Path { - return Path(NSString(string: self.path).stringByStandardizingPath) - } - - /// De-normalizes the path, by replacing the current user home directory with "~". - /// - /// - Returns: a new path made by removing extraneous path components from the underlying String - /// representation. - /// - public func abbreviate() -> Path { -#if os(Linux) - // TODO: actually de-normalize the path - return self + /// Test whether a path is absolute. + /// + /// - Returns: `true` iff the path begings with a slash + /// + public var isAbsolute: Bool { + return path.hasPrefix(Path.separator) + } + + /// Test whether a path is relative. + /// + /// - Returns: `true` iff a path is relative (not absolute) + /// + public var isRelative: Bool { + return !isAbsolute + } + + /// Concatenates relative paths to the current directory and derives the normalized path + /// + /// - Returns: the absolute path in the actual filesystem + /// + public func absolute() -> Path { + if isAbsolute { + return normalize() + } + + return (Path.current + self).normalize() + } + + /// Normalizes the path, this cleans up redundant ".." and ".", double slashes + /// and resolves "~". + /// + /// - Returns: a new path made by removing extraneous path components from the underlying String + /// representation. + /// + public func normalize() -> Path { +#if !swift(>=3.0) + return Path(NSString(string: self.path).stringByStandardizingPath) #else - return Path(NSString(string: self.path).stringByAbbreviatingWithTildeInPath) + return Path(NSString(string: self.path).standardizingPath) #endif - } - - /// Returns the path of the item pointed to by a symbolic link. - /// - /// - Returns: the path of directory or file to which the symbolic link refers - /// - public func symlinkDestination() throws -> Path { - let symlinkDestination = try Path.fileManager.destinationOfSymbolicLinkAtPath(path) - let symlinkPath = Path(symlinkDestination) - if symlinkPath.isRelative { - return self + ".." + symlinkPath - } else { - return symlinkPath } - } + + /// De-normalizes the path, by replacing the current user home directory with "~". + /// + /// - Returns: a new path made by removing extraneous path components from the underlying String + /// representation. + /// + public func abbreviate() -> Path { + #if os(Linux) + // TODO: actually de-normalize the path + return self + #else + #if !swift(>=3.0) + return Path(NSString(string: self.path).stringByAbbreviatingWithTildeInPath) + #else + return Path(NSString(string: self.path).abbreviatingWithTildeInPath) + #endif + #endif + } + + /// Returns the path of the item pointed to by a symbolic link. + /// + /// - Returns: the path of directory or file to which the symbolic link refers + /// + public func symlinkDestination() throws -> Path { + #if !swift(>=3.0) + let symlinkDestination = try Path.fileManager.destinationOfSymbolicLinkAtPath(path) + #else + let symlinkDestination = try Path.fileManager.destinationOfSymbolicLink(atPath:path) + #endif + let symlinkPath = Path(symlinkDestination) + if symlinkPath.isRelative { + return self + ".." + symlinkPath + } else { + return symlinkPath + } + } } // MARK: Path Components extension Path { - /// The last path component - /// - /// - Returns: the last path component - /// - public var lastComponent: String { - return NSString(string: path).lastPathComponent - } - - /// The last path component without file extension - /// - /// - Note: This returns "." for "..". - /// - /// - Returns: the last path component without file extension - /// - public var lastComponentWithoutExtension: String { - return NSString(string: lastComponent).stringByDeletingPathExtension - } - - /// Splits the string representation on the directory separator. - /// Absolute paths remain the leading slash as first component. - /// - /// - Returns: all path components - /// - public var components: [String] { - return NSString(string: path).pathComponents - } - - /// The file extension behind the last dot of the last component. - /// - /// - Returns: the file extension - /// - public var `extension`: String? { - let pathExtension = NSString(string: path).pathExtension - if pathExtension.isEmpty { - return nil - } - - return pathExtension - } + /// The last path component + /// + /// - Returns: the last path component + /// + public var lastComponent: String { + return NSString(string: path).lastPathComponent + } + + /// The last path component without file extension + /// + /// - Note: This returns "." for "..". + /// + /// - Returns: the last path component without file extension + /// + public var lastComponentWithoutExtension: String { + #if !swift(>=3.0) + return NSString(string: lastComponent).stringByDeletingPathExtension + #else + return NSString(string: lastComponent).deletingPathExtension + #endif + } + + /// Splits the string representation on the directory separator. + /// Absolute paths remain the leading slash as first component. + /// + /// - Returns: all path components + /// + public var components: [String] { + return NSString(string: path).pathComponents + } + + /// The file extension behind the last dot of the last component. + /// + /// - Returns: the file extension + /// + public var `extension`: String? { + let pathExtension = NSString(string: path).pathExtension + if pathExtension.isEmpty { + return nil + } + + return pathExtension + } } // MARK: File Info extension Path { - /// Test whether a file or directory exists at a specified path - /// - /// - Returns: `false` iff the path doesn't exist on disk or its existence could not be - /// determined - /// - public var exists: Bool { - return Path.fileManager.fileExistsAtPath(self.path) - } - - /// Test whether a path is a directory. - /// - /// - Returns: `true` if the path is a directory or a symbolic link that points to a directory; - /// `false` if the path is not a directory or the path doesn't exist on disk or its existence - /// could not be determined - /// - public var isDirectory: Bool { - var directory = ObjCBool(false) - guard Path.fileManager.fileExistsAtPath(normalize().path, isDirectory: &directory) else { - return false - } - return directory.boolValue - } - - /// Test whether a path is a regular file. - /// - /// - Returns: `true` if the path is neither a directory nor a symbolic link that points to a - /// directory; `false` if the path is a directory or a symbolic link that points to a - /// directory or the path doesn't exist on disk or its existence - /// could not be determined - /// - public var isFile: Bool { - var directory = ObjCBool(false) - guard Path.fileManager.fileExistsAtPath(normalize().path, isDirectory: &directory) else { - return false - } - return !directory.boolValue - } - - /// Test whether a path is a symbolic link. - /// - /// - Returns: `true` if the path is a symbolic link; `false` if the path doesn't exist on disk - /// or its existence could not be determined - /// - public var isSymlink: Bool { - do { - let _ = try Path.fileManager.destinationOfSymbolicLinkAtPath(path) - return true - } catch { - return false - } - } - - /// Test whether a path is readable - /// - /// - Returns: `true` if the current process has read privileges for the file at path; - /// otherwise `false` if the process does not have read privileges or the existence of the - /// file could not be determined. - /// - public var isReadable: Bool { - return Path.fileManager.isReadableFileAtPath(self.path) - } - - /// Test whether a path is writeable - /// - /// - Returns: `true` if the current process has write privileges for the file at path; - /// otherwise `false` if the process does not have write privileges or the existence of the - /// file could not be determined. - /// - public var isWritable: Bool { - return Path.fileManager.isWritableFileAtPath(self.path) - } - - /// Test whether a path is executable - /// - /// - Returns: `true` if the current process has execute privileges for the file at path; - /// otherwise `false` if the process does not have execute privileges or the existence of the - /// file could not be determined. - /// - public var isExecutable: Bool { - return Path.fileManager.isExecutableFileAtPath(self.path) - } - - /// Test whether a path is deletable - /// - /// - Returns: `true` if the current process has delete privileges for the file at path; - /// otherwise `false` if the process does not have delete privileges or the existence of the - /// file could not be determined. - /// - public var isDeletable: Bool { - return Path.fileManager.isDeletableFileAtPath(self.path) - } + /// Test whether a file or directory exists at a specified path + /// + /// - Returns: `false` iff the path doesn't exist on disk or its existence could not be + /// determined + /// + public var exists: Bool { + #if !swift(>=3.0) + return Path.fileManager.fileExistsAtPath(self.path) + #else + return Path.fileManager.fileExists(atPath:self.path) + #endif + } + + /// Test whether a path is a directory. + /// + /// - Returns: `true` if the path is a directory or a symbolic link that points to a directory; + /// `false` if the path is not a directory or the path doesn't exist on disk or its existence + /// could not be determined + /// + public var isDirectory: Bool { + var directory = ObjCBool(false) + #if !swift(>=3.0) + guard Path.fileManager.fileExistsAtPath(normalize().path, isDirectory: &directory) else { + return false + } + #else + guard Path.fileManager.fileExists(atPath: normalize().path, isDirectory: &directory) else { + return false + } + #endif + return directory.boolValue + } + + /// Test whether a path is a regular file. + /// + /// - Returns: `true` if the path is neither a directory nor a symbolic link that points to a + /// directory; `false` if the path is a directory or a symbolic link that points to a + /// directory or the path doesn't exist on disk or its existence + /// could not be determined + /// + public var isFile: Bool { + var directory = ObjCBool(false) + #if !swift(>=3.0) + guard Path.fileManager.fileExistsAtPath(normalize().path, isDirectory: &directory) else { + return false + } + #else + guard Path.fileManager.fileExists(atPath: normalize().path, isDirectory: &directory) else { + return false + } + #endif + return !directory.boolValue + } + + /// Test whether a path is a symbolic link. + /// + /// - Returns: `true` if the path is a symbolic link; `false` if the path doesn't exist on disk + /// or its existence could not be determined + /// + public var isSymlink: Bool { + do { + #if !swift(>=3.0) + let _ = try Path.fileManager.destinationOfSymbolicLinkAtPath(path) + #else + let _ = try Path.fileManager.destinationOfSymbolicLink(atPath: path) + #endif + return true + } catch { + return false + } + } + + /// Test whether a path is readable + /// + /// - Returns: `true` if the current process has read privileges for the file at path; + /// otherwise `false` if the process does not have read privileges or the existence of the + /// file could not be determined. + /// + public var isReadable: Bool { + #if !swift(>=3.0) + return Path.fileManager.isReadableFileAtPath(self.path) + #else + return Path.fileManager.isReadableFile(atPath: self.path) + #endif + } + + /// Test whether a path is writeable + /// + /// - Returns: `true` if the current process has write privileges for the file at path; + /// otherwise `false` if the process does not have write privileges or the existence of the + /// file could not be determined. + /// + public var isWritable: Bool { + #if !swift(>=3.0) + return Path.fileManager.isWritableFileAtPath(self.path) + #else + return Path.fileManager.isWritableFile(atPath: self.path) + #endif + } + + /// Test whether a path is executable + /// + /// - Returns: `true` if the current process has execute privileges for the file at path; + /// otherwise `false` if the process does not have execute privileges or the existence of the + /// file could not be determined. + /// + public var isExecutable: Bool { + #if !swift(>=3.0) + return Path.fileManager.isExecutableFileAtPath(self.path) + #else + return Path.fileManager.isExecutableFile(atPath: self.path) + #endif + } + + /// Test whether a path is deletable + /// + /// - Returns: `true` if the current process has delete privileges for the file at path; + /// otherwise `false` if the process does not have delete privileges or the existence of the + /// file could not be determined. + /// + public var isDeletable: Bool { + #if !swift(>=3.0) + return Path.fileManager.isDeletableFileAtPath(self.path) + #else + return Path.fileManager.isDeletableFile(atPath: self.path) + #endif + } } // MARK: File Manipulation extension Path { - /// Create the directory. - /// - /// - Note: This method fails if any of the intermediate parent directories does not exist. - /// This method also fails if any of the intermediate path elements corresponds to a file and - /// not a directory. - /// - public func mkdir() throws -> () { - try Path.fileManager.createDirectoryAtPath(self.path, withIntermediateDirectories: false, attributes: nil) - } - - /// Create the directory and any intermediate parent directories that do not exist. - /// - /// - Note: This method fails if any of the intermediate path elements corresponds to a file and - /// not a directory. - /// - public func mkpath() throws -> () { - try Path.fileManager.createDirectoryAtPath(self.path, withIntermediateDirectories: true, attributes: nil) - } - - /// Delete the file or directory. - /// - /// - Note: If the path specifies a directory, the contents of that directory are recursively - /// removed. - /// - public func delete() throws -> () { - try Path.fileManager.removeItemAtPath(self.path) - } - - /// Move the file or directory to a new location synchronously. - /// - /// - Parameter destination: The new path. This path must include the name of the file or - /// directory in its new location. - /// - public func move(destination: Path) throws -> () { - try Path.fileManager.moveItemAtPath(self.path, toPath: destination.path) - } - - /// Copy the file or directory to a new location synchronously. - /// - /// - Parameter destination: The new path. This path must include the name of the file or - /// directory in its new location. - /// - public func copy(destination: Path) throws -> () { - try Path.fileManager.copyItemAtPath(self.path, toPath: destination.path) - } - - /// Creates a hard link at a new destination. - /// - /// - Parameter destination: The location where the link will be created. - /// - public func link(destination: Path) throws -> () { - try Path.fileManager.linkItemAtPath(self.path, toPath: destination.path) - } - - /// Creates a symbolic link at a new destination. - /// - /// - Parameter destintation: The location where the link will be created. - /// - public func symlink(destination: Path) throws -> () { - try Path.fileManager.createSymbolicLinkAtPath(self.path, withDestinationPath: destination.path) - } + /// Create the directory. + /// + /// - Note: This method fails if any of the intermediate parent directories does not exist. + /// This method also fails if any of the intermediate path elements corresponds to a file and + /// not a directory. + /// + public func mkdir() throws -> () { + #if !swift(>=3.0) + try Path.fileManager.createDirectoryAtPath(self.path, withIntermediateDirectories: false, attributes: nil) + #else + try Path.fileManager.createDirectory(atPath: self.path, withIntermediateDirectories: false, attributes: nil) + #endif + } + + /// Create the directory and any intermediate parent directories that do not exist. + /// + /// - Note: This method fails if any of the intermediate path elements corresponds to a file and + /// not a directory. + /// + public func mkpath() throws -> () { + #if !swift(>=3.0) + try Path.fileManager.createDirectoryAtPath(self.path, withIntermediateDirectories: true, attributes: nil) + #else + try Path.fileManager.createDirectory(atPath: self.path, withIntermediateDirectories: true, attributes: nil) + #endif + } + + /// Delete the file or directory. + /// + /// - Note: If the path specifies a directory, the contents of that directory are recursively + /// removed. + /// + public func delete() throws -> () { + #if !swift(>=3.0) + try Path.fileManager.removeItemAtPath(self.path) + #else + try Path.fileManager.removeItem(atPath: self.path) + #endif + } + + /// Move the file or directory to a new location synchronously. + /// + /// - Parameter destination: The new path. This path must include the name of the file or + /// directory in its new location. + /// + public func move(destination: Path) throws -> () { + #if !swift(>=3.0) + try Path.fileManager.moveItemAtPath(self.path, toPath: destination.path) + #else + try Path.fileManager.moveItem(atPath: self.path, toPath: destination.path) + #endif + } + + /// Copy the file or directory to a new location synchronously. + /// + /// - Parameter destination: The new path. This path must include the name of the file or + /// directory in its new location. + /// + public func copy(destination: Path) throws -> () { + #if !swift(>=3.0) + try Path.fileManager.copyItemAtPath(self.path, toPath: destination.path) + #else + try Path.fileManager.copyItem(atPath: self.path, toPath: destination.path) + #endif + } + + /// Creates a hard link at a new destination. + /// + /// - Parameter destination: The location where the link will be created. + /// + public func link(destination: Path) throws -> () { + #if !swift(>=3.0) + try Path.fileManager.linkItemAtPath(self.path, toPath: destination.path) + #else + try Path.fileManager.linkItem(atPath: self.path, toPath: destination.path) + #endif + } + + /// Creates a symbolic link at a new destination. + /// + /// - Parameter destintation: The location where the link will be created. + /// + public func symlink(destination: Path) throws -> () { + #if !swift(>=3.0) + try Path.fileManager.createSymbolicLinkAtPath(self.path, withDestinationPath: destination.path) + #else + try Path.fileManager.createSymbolicLink(atPath: self.path, withDestinationPath: destination.path) + #endif + } } // MARK: Current Directory extension Path { - /// The current working directory of the process - /// - /// - Returns: the current working directory of the process - /// - public static var current: Path { - get { - return self.init(Path.fileManager.currentDirectoryPath) - } - set { - Path.fileManager.changeCurrentDirectoryPath(newValue.description) - } - } - - /// Changes the current working directory of the process to the path during the execution of the - /// given block. - /// - /// - Note: The original working directory is restored when the block returns or throws. - /// - Parameter closure: A closure to be executed while the current directory is configured to - /// the path. - /// - public func chdir(@noescape closure: () throws -> ()) rethrows { - let previous = Path.current - Path.current = self - defer { Path.current = previous } - try closure() + /// The current working directory of the process + /// + /// - Returns: the current working directory of the process + /// + public static var current: Path { + get { + return self.init(Path.fileManager.currentDirectoryPath) + } + set { + Path.fileManager.changeCurrentDirectoryPath(newValue.description) + } + } + + /// Changes the current working directory of the process to the path during the execution of the + /// given block. + /// + /// - Note: The original working directory is restored when the block returns or throws. + /// - Parameter closure: A closure to be executed while the current directory is configured to + /// the path. + /// + public func chdir(@noescape closure: () throws -> ()) rethrows { + let previous = Path.current + Path.current = self + defer { Path.current = previous } + try closure() } } @@ -407,211 +515,262 @@ extension Path { // MARK: Temporary extension Path { - /// - Returns: the path to either the user’s or application’s home directory, - /// depending on the platform. - /// - public static var home: Path { -#if os(Linux) - return Path(NSProcessInfo.processInfo().environment["HOME"] ?? "/") -#else - return Path(NSHomeDirectory()) -#endif - } - - /// - Returns: the path of the temporary directory for the current user. - /// - public static var temporary: Path { -#if os(Linux) - return Path(NSProcessInfo.processInfo().environment["TMP"] ?? "/tmp") -#else - return Path(NSTemporaryDirectory()) -#endif - } - - /// - Returns: the path of a temporary directory unique for the process. - /// - Note: Based on `NSProcessInfo.globallyUniqueString`. - /// - public static func processUniqueTemporary() throws -> Path { - let path = temporary + NSProcessInfo.processInfo().globallyUniqueString - if !path.exists { - try path.mkdir() - } - return path - } - - /// - Returns: the path of a temporary directory unique for each call. - /// - Note: Based on `NSUUID`. - /// - public static func uniqueTemporary() throws -> Path { - let path = try processUniqueTemporary() + NSUUID().UUIDString - try path.mkdir() - return path - } + /// - Returns: the path to either the user’s or application’s home directory, + /// depending on the platform. + /// + public static var home: Path { + #if os(Linux) + return Path(NSProcessInfo.processInfo().environment["HOME"] ?? "/") + #else + return Path(NSHomeDirectory()) + #endif + } + + /// - Returns: the path of the temporary directory for the current user. + /// + public static var temporary: Path { + #if os(Linux) + return Path(NSProcessInfo.processInfo().environment["TMP"] ?? "/tmp") + #else + return Path(NSTemporaryDirectory()) + #endif + } + + /// - Returns: the path of a temporary directory unique for the process. + /// - Note: Based on `NSProcessInfo.globallyUniqueString`. + /// + public static func processUniqueTemporary() throws -> Path { + let path = temporary + NSProcessInfo.processInfo().globallyUniqueString + if !path.exists { + try path.mkdir() + } + return path + } + + /// - Returns: the path of a temporary directory unique for each call. + /// - Note: Based on `NSUUID`. + /// + public static func uniqueTemporary() throws -> Path { + #if !swift(>=3.0) + let path = try processUniqueTemporary() + NSUUID().UUIDString + #else + let path = try processUniqueTemporary() + NSUUID().uuidString + #endif + try path.mkdir() + return path + } } // MARK: Contents extension Path { - /// Reads the file. - /// - /// - Returns: the contents of the file at the specified path. - /// - public func read() throws -> NSData { - return try NSData(contentsOfFile: path, options: NSDataReadingOptions(rawValue: 0)) - } - - /// Reads the file contents and encoded its bytes to string applying the given encoding. - /// - /// - Parameter encoding: the encoding which should be used to decode the data. - /// (by default: `NSUTF8StringEncoding`) - /// - /// - Returns: the contents of the file at the specified path as string. - /// - public func read(encoding: NSStringEncoding = NSUTF8StringEncoding) throws -> String { - return try NSString(contentsOfFile: path, encoding: encoding).substringFromIndex(0) as String - } - - /// Write a file. - /// - /// - Note: Works atomically: the data is written to a backup file, and then — assuming no - /// errors occur — the backup file is renamed to the name specified by path. - /// - /// - Parameter data: the contents to write to file. - /// - public func write(data: NSData) throws { - try data.writeToFile(normalize().path, options: .DataWritingAtomic) - } - - /// Reads the file. - /// - /// - Note: Works atomically: the data is written to a backup file, and then — assuming no - /// errors occur — the backup file is renamed to the name specified by path. - /// - /// - Parameter string: the string to write to file. - /// - /// - Parameter encoding: the encoding which should be used to represent the string as bytes. - /// (by default: `NSUTF8StringEncoding`) - /// - /// - Returns: the contents of the file at the specified path as string. - /// - public func write(string: String, encoding: NSStringEncoding = NSUTF8StringEncoding) throws { - try NSString(string: string).writeToFile(normalize().path, atomically: true, encoding: encoding) - } + /// Reads the file. + /// + /// - Returns: the contents of the file at the specified path. + /// + public func read() throws -> NSData { + return try NSData(contentsOfFile: path, options: NSDataReadingOptions(rawValue: 0)) + } + + /// Reads the file contents and encoded its bytes to string applying the given encoding. + /// + /// - Parameter encoding: the encoding which should be used to decode the data. + /// (by default: `NSUTF8StringEncoding`) + /// + /// - Returns: the contents of the file at the specified path as string. + /// + public func read(encoding: NSStringEncoding = NSUTF8StringEncoding) throws -> String { + #if !swift(>=3.0) + return try NSString(contentsOfFile: path, encoding: encoding).substringFromIndex(0) as String + #else + return try NSString(contentsOfFile: path, encoding: encoding).substring(from:0) as String + #endif + } + + /// Write a file. + /// + /// - Note: Works atomically: the data is written to a backup file, and then — assuming no + /// errors occur — the backup file is renamed to the name specified by path. + /// + /// - Parameter data: the contents to write to file. + /// + public func write(data: NSData) throws { + #if !swift(>=3.0) + try data.writeToFile(normalize().path, options: .DataWritingAtomic) + #else + try data.write(toFile:normalize().path, options: .dataWritingAtomic) + #endif + } + + /// Reads the file. + /// + /// - Note: Works atomically: the data is written to a backup file, and then — assuming no + /// errors occur — the backup file is renamed to the name specified by path. + /// + /// - Parameter string: the string to write to file. + /// + /// - Parameter encoding: the encoding which should be used to represent the string as bytes. + /// (by default: `NSUTF8StringEncoding`) + /// + /// - Returns: the contents of the file at the specified path as string. + /// + public func write(string: String, encoding: NSStringEncoding = NSUTF8StringEncoding) throws { + #if !swift(>=3.0) + try NSString(string: string).writeToFile(normalize().path, atomically: true, encoding: encoding) + #else + try NSString(string: string).write(toFile:normalize().path, atomically: true, encoding: encoding) + #endif + } } // MARK: Traversing extension Path { - /// Get the parent directory - /// - /// - Returns: the normalized path of the parent directory - /// - public func parent() -> Path { - return self + ".." - } - - /// Performs a shallow enumeration in a directory - /// - /// - Returns: paths to all files, directories and symbolic links contained in the directory - /// - public func children() throws -> [Path] { - return try Path.fileManager.contentsOfDirectoryAtPath(path).map { - self + Path($0) - } - } - - /// Performs a deep enumeration in a directory - /// - /// - Returns: paths to all files, directories and symbolic links contained in the directory or - /// any subdirectory. - /// - public func recursiveChildren() throws -> [Path] { - return try Path.fileManager.subpathsOfDirectoryAtPath(path).map { - self + Path($0) - } - } + /// Get the parent directory + /// + /// - Returns: the normalized path of the parent directory + /// + public func parent() -> Path { + return self + ".." + } + + /// Performs a shallow enumeration in a directory + /// + /// - Returns: paths to all files, directories and symbolic links contained in the directory + /// + public func children() throws -> [Path] { + #if !swift(>=3.0) + return try Path.fileManager.contentsOfDirectoryAtPath(path).map { + self + Path($0) + } + #else + return try Path.fileManager.contentsOfDirectory(atPath:path).map { + self + Path($0) + } + #endif + + } + + /// Performs a deep enumeration in a directory + /// + /// - Returns: paths to all files, directories and symbolic links contained in the directory or + /// any subdirectory. + /// + public func recursiveChildren() throws -> [Path] { + #if !swift(>=3.0) + return try Path.fileManager.subpathsOfDirectoryAtPath(path).map { + self + Path($0) + } + #else + return try Path.fileManager.subpathsOfDirectory(atPath:path).map { + self + Path($0) + } + #endif + } } // MARK: Globbing extension Path { - public static func glob(pattern: String) -> [Path] { - var gt = glob_t() - let cPattern = strdup(pattern) - defer { - globfree(>) - free(cPattern) - } - - let flags = GLOB_TILDE | GLOB_BRACE | GLOB_MARK - if system_glob(cPattern, flags, nil, >) == 0 { -#if os(Linux) - let matchc = gt.gl_pathc -#else - let matchc = gt.gl_matchc -#endif - return (0.. [Path] { + var gt = glob_t() + let cPattern = strdup(pattern) + defer { + globfree(>) + free(cPattern) } - - return nil - } + + let flags = GLOB_TILDE | GLOB_BRACE | GLOB_MARK + if system_glob(cPattern, flags, nil, >) == 0 { + #if os(Linux) + let matchc = gt.gl_pathc + #else + let matchc = gt.gl_matchc + #endif + #if !swift(>=3.0) + return (0.. [Path] { + return Path.glob((self + pattern).description) } - - // GLOB_NOMATCH - return [] - } - - public func glob(pattern: String) -> [Path] { - return Path.glob((self + pattern).description) - } } // MARK: SequenceType -extension Path : SequenceType { - /// Enumerates the contents of a directory, returning the paths of all files and directories - /// contained within that directory. These paths are relative to the directory. - public struct DirectoryEnumerator : GeneratorType { - public typealias Element = Path - - let path: Path - let directoryEnumerator: NSDirectoryEnumerator - - init(path: Path) { - self.path = path - self.directoryEnumerator = Path.fileManager.enumeratorAtPath(path.path)! - } - - public func next() -> Path? { - if let next = directoryEnumerator.nextObject() as! String? { - return path + next - } - return nil +extension Path : Sequence { + /// Enumerates the contents of a directory, returning the paths of all files and directories + /// contained within that directory. These paths are relative to the directory. + public struct DirectoryEnumerator : IteratorProtocol { + public typealias Element = Path + + let path: Path + let directoryEnumerator: NSDirectoryEnumerator + + init(path: Path) { + self.path = path + #if !swift(>=3.0) + self.directoryEnumerator = Path.fileManager.enumeratorAtPath(path.path)! + #else + self.directoryEnumerator = Path.fileManager.enumerator(atPath:path.path)! + #endif + } + + public func next() -> Path? { + if let next = directoryEnumerator.nextObject() as! String? { + return path + next + } + return nil + } + + /// Skip recursion into the most recently obtained subdirectory. + public func skipDescendants() { + directoryEnumerator.skipDescendants() + } } - - /// Skip recursion into the most recently obtained subdirectory. - public func skipDescendants() { - directoryEnumerator.skipDescendants() + + /// Perform a deep enumeration of a directory. + /// + /// - Returns: a directory enumerator that can be used to perform a deep enumeration of the + /// directory. + /// + #if !swift(>=3.0) + public func generate() -> DirectoryEnumerator { + return DirectoryEnumerator(path: self) } - } - - /// Perform a deep enumeration of a directory. - /// - /// - Returns: a directory enumerator that can be used to perform a deep enumeration of the - /// directory. - /// - public func generate() -> DirectoryEnumerator { + #else + public func makeIterator() -> DirectoryEnumerator { return DirectoryEnumerator(path: self) - } + } + #endif } + + // MARK: Equatable extension Path : Equatable {} @@ -622,7 +781,7 @@ extension Path : Equatable {} /// ./foo.txt) can refer to the same file. /// public func ==(lhs: Path, rhs: Path) -> Bool { - return lhs.path == rhs.path + return lhs.path == rhs.path } @@ -635,8 +794,8 @@ public func ==(lhs: Path, rhs: Path) -> Bool { /// - the paths can be normalized to equal Paths. /// public func ~=(lhs: Path, rhs: Path) -> Bool { - return lhs == rhs - || lhs.normalize() == rhs.normalize() + return lhs == rhs + || lhs.normalize() == rhs.normalize() } @@ -646,7 +805,7 @@ extension Path : Comparable {} /// Defines a strict total order over Paths based on their underlying string representation. public func <(lhs: Path, rhs: Path) -> Bool { - return lhs.path < rhs.path + return lhs.path < rhs.path } @@ -654,58 +813,58 @@ public func <(lhs: Path, rhs: Path) -> Bool { /// Appends a Path fragment to another Path to produce a new Path public func +(lhs: Path, rhs: Path) -> Path { - return lhs.path + rhs.path + return lhs.path + rhs.path } /// Appends a String fragment to another Path to produce a new Path public func +(lhs: Path, rhs: String) -> Path { - return lhs.path + rhs + return lhs.path + rhs } /// Appends a String fragment to another String to produce a new Path internal func +(lhs: String, rhs: String) -> Path { - if rhs.hasPrefix(Path.separator) { - // Absolute paths replace relative paths - return Path(rhs) - } else { - var lSlice = NSString(string: lhs).pathComponents.fullSlice - var rSlice = NSString(string: rhs).pathComponents.fullSlice - - // Get rid of trailing "/" at the left side - if lSlice.count > 1 && lSlice.last == Path.separator { - lSlice.removeLast() - } - - // Advance after the first relevant "." - lSlice = lSlice.filter { $0 != "." }.fullSlice - rSlice = rSlice.filter { $0 != "." }.fullSlice - - // Eats up trailing components of the left and leading ".." of the right side - while lSlice.last != ".." && rSlice.first == ".." { - if (lSlice.count > 1 || lSlice.first != Path.separator) && !lSlice.isEmpty { - // A leading "/" is never popped - lSlice.removeLast() - } - if !rSlice.isEmpty { - rSlice.removeFirst() - } - - switch (lSlice.isEmpty, rSlice.isEmpty) { - case (true, _): - break - case (_, true): - break - default: - continue - } - } - - return Path(components: lSlice + rSlice) - } + if rhs.hasPrefix(Path.separator) { + // Absolute paths replace relative paths + return Path(rhs) + } else { + var lSlice = NSString(string: lhs).pathComponents.fullSlice + var rSlice = NSString(string: rhs).pathComponents.fullSlice + + // Get rid of trailing "/" at the left side + if lSlice.count > 1 && lSlice.last == Path.separator { + lSlice.removeLast() + } + + // Advance after the first relevant "." + lSlice = lSlice.filter { $0 != "." }.fullSlice + rSlice = rSlice.filter { $0 != "." }.fullSlice + + // Eats up trailing components of the left and leading ".." of the right side + while lSlice.last != ".." && rSlice.first == ".." { + if (lSlice.count > 1 || lSlice.first != Path.separator) && !lSlice.isEmpty { + // A leading "/" is never popped + lSlice.removeLast() + } + if !rSlice.isEmpty { + rSlice.removeFirst() + } + + switch (lSlice.isEmpty, rSlice.isEmpty) { + case (true, _): + break + case (_, true): + break + default: + continue + } + } + + return Path(components: lSlice + rSlice) + } } extension Array { - var fullSlice: ArraySlice { - return self[0.. { + return self[0.. Date: Thu, 31 Mar 2016 16:55:14 +0200 Subject: [PATCH 2/5] Added support for swift 3.0 (DEVELOPMENT-SNAPSHOT-2016-03-24-a) --- Pods/CatchingFire/src/CatchingFire.swift | 18 ++-- Sources/PathKit.swift | 112 +++++++++++------------ 2 files changed, 67 insertions(+), 63 deletions(-) diff --git a/Pods/CatchingFire/src/CatchingFire.swift b/Pods/CatchingFire/src/CatchingFire.swift index 0ced4f1..085deb8 100644 --- a/Pods/CatchingFire/src/CatchingFire.swift +++ b/Pods/CatchingFire/src/CatchingFire.swift @@ -8,6 +8,10 @@ import XCTest +#if !swift(>=3.0) + typealias ErrorProtocol = ErrorType +#endif + /// This allows you to write safe tests for the happy path of failable functions. /// It helps you to avoid the `try!` operator in tests. @@ -77,11 +81,11 @@ public func AssertNoThrow(@noescape closure: () throws -> ()) { /// /// If the expression or closure doesn't throw the expected error, your test fails. /// -public func AssertThrows(expectedError: E, @autoclosure _ closure: () throws -> R) -> () { +public func AssertThrows(expectedError: E, @autoclosure _ closure: () throws -> R) -> () { AssertThrows(expectedError) { try closure() } } -public func AssertThrows(expectedError: E, @noescape _ closure: () throws -> ()) -> () { +public func AssertThrows(expectedError: E, @noescape _ closure: () throws -> ()) -> () { do { try closure() XCTFail("Expected to catch <\(expectedError)>, " @@ -95,11 +99,11 @@ public func AssertThrows(expectedError: E, @noescape _ clo } } -public func AssertThrows(expectedError: E, @autoclosure _ closure: () throws -> R) -> () { +public func AssertThrows(expectedError: E, @autoclosure _ closure: () throws -> R) -> () { AssertThrows(expectedError) { try closure() } } -public func AssertThrows(expectedError: E, @noescape _ closure: () throws -> ()) -> () { +public func AssertThrows(expectedError: E, @noescape _ closure: () throws -> ()) -> () { do { try closure() XCTFail("Expected to catch <\(expectedError)>, " @@ -116,7 +120,7 @@ public func AssertThrows(expectedError: E, @ } /// Implement pattern matching for ErrorTypes -internal func ~=(lhs: ErrorType, rhs: ErrorType) -> Bool { +internal func ~=(lhs: ErrorProtocol, rhs: ErrorProtocol) -> Bool { return lhs._domain == rhs._domain && rhs._code == rhs._code } @@ -131,7 +135,7 @@ internal func ~=(lhs: ErrorType, rhs: ErrorType) -> Bool { //// put them in a separate enum and import your framework as `@testable` in your tests without /// affecting the public API, if that matters. /// -public struct Error : ErrorType { +public struct Error : ErrorProtocol { public let domain: String public let code: Int @@ -153,7 +157,7 @@ public func ==(lhs: Error, rhs: Error) -> Bool { } /// Implement pattern matching for Error & ErrorType -public func ~=(lhs: Error, rhs: ErrorType) -> Bool { +public func ~=(lhs: Error, rhs: ErrorProtocol) -> Bool { return lhs._domain == rhs._domain && rhs._code == rhs._code } diff --git a/Sources/PathKit.swift b/Sources/PathKit.swift index 7bcf7ae..2f37459 100644 --- a/Sources/PathKit.swift +++ b/Sources/PathKit.swift @@ -46,38 +46,38 @@ public struct Path { /// Create a Path by joining multiple path components together #if !swift(>=3.0) public init(components: S) { - if components.isEmpty { - path = "." - } else if components.first == Path.separator && components.count > 1 { - let p = components.joinWithSeparator(Path.separator) - #if os(Linux) - let index = p.startIndex.distanceTo(p.startIndex.successor()) - path = NSString(string: p).substringFromIndex(index) - #else - path = p.substringFromIndex(p.startIndex.successor()) - #endif - - } else { - path = components.joinWithSeparator(Path.separator) - } - } - #else - public init(components: S) { if components.isEmpty { path = "." } else if components.first == Path.separator && components.count > 1 { - let p = components.joined(separator: Path.separator) + let p = components.joinWithSeparator(Path.separator) #if os(Linux) let index = p.startIndex.distanceTo(p.startIndex.successor()) path = NSString(string: p).substringFromIndex(index) #else - path = p.substring(from: p.startIndex.successor()) + path = p.substringFromIndex(p.startIndex.successor()) #endif } else { - path = components.joined(separator: Path.separator) + path = components.joinWithSeparator(Path.separator) } } + #else + public init(components: S) { + if components.isEmpty { + path = "." + } else if components.first == Path.separator && components.count > 1 { + let p = components.joined(separator: Path.separator) + #if os(Linux) + let index = p.startIndex.distanceTo(p.startIndex.successor()) + path = NSString(string: p).substringFromIndex(index) + #else + path = p.substring(from: p.startIndex.successor()) + #endif + + } else { + path = components.joined(separator: Path.separator) + } + } #endif } @@ -158,11 +158,11 @@ extension Path { /// representation. /// public func normalize() -> Path { -#if !swift(>=3.0) - return Path(NSString(string: self.path).stringByStandardizingPath) -#else - return Path(NSString(string: self.path).standardizingPath) -#endif + #if !swift(>=3.0) + return Path(NSString(string: self.path).stringByStandardizingPath) + #else + return Path(NSString(string: self.path).standardizingPath) + #endif } /// De-normalizes the path, by replacing the current user home directory with "~". @@ -176,10 +176,10 @@ extension Path { return self #else #if !swift(>=3.0) - return Path(NSString(string: self.path).stringByAbbreviatingWithTildeInPath) + return Path(NSString(string: self.path).stringByAbbreviatingWithTildeInPath) #else - return Path(NSString(string: self.path).abbreviatingWithTildeInPath) - #endif + return Path(NSString(string: self.path).abbreviatingWithTildeInPath) + #endif #endif } @@ -222,9 +222,9 @@ extension Path { /// public var lastComponentWithoutExtension: String { #if !swift(>=3.0) - return NSString(string: lastComponent).stringByDeletingPathExtension + return NSString(string: lastComponent).stringByDeletingPathExtension #else - return NSString(string: lastComponent).deletingPathExtension + return NSString(string: lastComponent).deletingPathExtension #endif } @@ -262,7 +262,7 @@ extension Path { /// public var exists: Bool { #if !swift(>=3.0) - return Path.fileManager.fileExistsAtPath(self.path) + return Path.fileManager.fileExistsAtPath(self.path) #else return Path.fileManager.fileExists(atPath:self.path) #endif @@ -277,9 +277,9 @@ extension Path { public var isDirectory: Bool { var directory = ObjCBool(false) #if !swift(>=3.0) - guard Path.fileManager.fileExistsAtPath(normalize().path, isDirectory: &directory) else { + guard Path.fileManager.fileExistsAtPath(normalize().path, isDirectory: &directory) else { return false - } + } #else guard Path.fileManager.fileExists(atPath: normalize().path, isDirectory: &directory) else { return false @@ -299,7 +299,7 @@ extension Path { var directory = ObjCBool(false) #if !swift(>=3.0) guard Path.fileManager.fileExistsAtPath(normalize().path, isDirectory: &directory) else { - return false + return false } #else guard Path.fileManager.fileExists(atPath: normalize().path, isDirectory: &directory) else { @@ -552,9 +552,9 @@ extension Path { /// public static func uniqueTemporary() throws -> Path { #if !swift(>=3.0) - let path = try processUniqueTemporary() + NSUUID().UUIDString + let path = try processUniqueTemporary() + NSUUID().UUIDString #else - let path = try processUniqueTemporary() + NSUUID().uuidString + let path = try processUniqueTemporary() + NSUUID().uuidString #endif try path.mkdir() return path @@ -582,9 +582,9 @@ extension Path { /// public func read(encoding: NSStringEncoding = NSUTF8StringEncoding) throws -> String { #if !swift(>=3.0) - return try NSString(contentsOfFile: path, encoding: encoding).substringFromIndex(0) as String + return try NSString(contentsOfFile: path, encoding: encoding).substringFromIndex(0) as String #else - return try NSString(contentsOfFile: path, encoding: encoding).substring(from:0) as String + return try NSString(contentsOfFile: path, encoding: encoding).substring(from:0) as String #endif } @@ -617,9 +617,9 @@ extension Path { /// public func write(string: String, encoding: NSStringEncoding = NSUTF8StringEncoding) throws { #if !swift(>=3.0) - try NSString(string: string).writeToFile(normalize().path, atomically: true, encoding: encoding) + try NSString(string: string).writeToFile(normalize().path, atomically: true, encoding: encoding) #else - try NSString(string: string).write(toFile:normalize().path, atomically: true, encoding: encoding) + try NSString(string: string).write(toFile:normalize().path, atomically: true, encoding: encoding) #endif } } @@ -642,12 +642,12 @@ extension Path { /// public func children() throws -> [Path] { #if !swift(>=3.0) - return try Path.fileManager.contentsOfDirectoryAtPath(path).map { + return try Path.fileManager.contentsOfDirectoryAtPath(path).map { self + Path($0) } #else - return try Path.fileManager.contentsOfDirectory(atPath:path).map { - self + Path($0) + return try Path.fileManager.contentsOfDirectory(atPath:path).map { + self + Path($0) } #endif @@ -660,13 +660,13 @@ extension Path { /// public func recursiveChildren() throws -> [Path] { #if !swift(>=3.0) - return try Path.fileManager.subpathsOfDirectoryAtPath(path).map { + return try Path.fileManager.subpathsOfDirectoryAtPath(path).map { self + Path($0) - } + } #else - return try Path.fileManager.subpathsOfDirectory(atPath:path).map { - self + Path($0) - } + return try Path.fileManager.subpathsOfDirectory(atPath:path).map { + self + Path($0) + } #endif } } @@ -691,20 +691,20 @@ extension Path { let matchc = gt.gl_matchc #endif #if !swift(>=3.0) - return (0..=3.0) public func generate() -> DirectoryEnumerator { - return DirectoryEnumerator(path: self) + return DirectoryEnumerator(path: self) } #else public func makeIterator() -> DirectoryEnumerator { - return DirectoryEnumerator(path: self) + return DirectoryEnumerator(path: self) } #endif } From f5ae0ddba7d1a41426db5fa8f2ff83dbbe895918 Mon Sep 17 00:00:00 2001 From: Alex Tran Qui Date: Thu, 31 Mar 2016 22:07:40 +0200 Subject: [PATCH 3/5] As suggested on PR review, changed !swift(>=3.0) to swift(<3.0) and fixed indentation changes. --- Sources/PathKit.swift | 1409 ++++++++++++++++++++--------------------- 1 file changed, 703 insertions(+), 706 deletions(-) diff --git a/Sources/PathKit.swift b/Sources/PathKit.swift index 2f37459..138bbd8 100644 --- a/Sources/PathKit.swift +++ b/Sources/PathKit.swift @@ -1,771 +1,768 @@ // PathKit - Effortless path operations #if os(Linux) - import Glibc - +import Glibc + let system_glob = Glibc.glob #else - import Darwin - +import Darwin + let system_glob = Darwin.glob #endif import Foundation - -#if !swift(>=3.0) - typealias Collection = CollectionType - typealias Sequence = SequenceType - typealias IteratorProtocol = GeneratorType - - +#if swift(<3.0) + typealias Collection = CollectionType + typealias Sequence = SequenceType + typealias IteratorProtocol = GeneratorType #endif /// Represents a filesystem path. public struct Path { - /// The character used by the OS to separate two path elements - public static let separator = "/" - - /// The underlying string representation - internal var path: String - - internal static var fileManager = NSFileManager.defaultManager() - - // MARK: Init - - public init() { - self.path = "" - } - - /// Create a Path from a given String - public init(_ path: String) { - self.path = path - } - - /// Create a Path by joining multiple path components together - #if !swift(>=3.0) - public init(components: S) { + /// The character used by the OS to separate two path elements + public static let separator = "/" + + /// The underlying string representation + internal var path: String + + internal static var fileManager = NSFileManager.defaultManager() + + // MARK: Init + + public init() { + self.path = "" + } + + /// Create a Path from a given String + public init(_ path: String) { + self.path = path + } + + /// Create a Path by joining multiple path components together + #if swift(<3.0) + public init(components: S) { if components.isEmpty { - path = "." + path = "." } else if components.first == Path.separator && components.count > 1 { - let p = components.joinWithSeparator(Path.separator) - #if os(Linux) - let index = p.startIndex.distanceTo(p.startIndex.successor()) - path = NSString(string: p).substringFromIndex(index) - #else - path = p.substringFromIndex(p.startIndex.successor()) - #endif - + let p = components.joinWithSeparator(Path.separator) +#if os(Linux) + let index = p.startIndex.distanceTo(p.startIndex.successor()) + path = NSString(string: p).substringFromIndex(index) +#else + path = p.substringFromIndex(p.startIndex.successor()) +#endif + } else { - path = components.joinWithSeparator(Path.separator) + path = components.joinWithSeparator(Path.separator) } } - #else - public init(components: S) { - if components.isEmpty { - path = "." - } else if components.first == Path.separator && components.count > 1 { - let p = components.joined(separator: Path.separator) - #if os(Linux) - let index = p.startIndex.distanceTo(p.startIndex.successor()) - path = NSString(string: p).substringFromIndex(index) - #else - path = p.substring(from: p.startIndex.successor()) - #endif - - } else { - path = components.joined(separator: Path.separator) - } + #else + public init(components: S) { + if components.isEmpty { + path = "." + } else if components.first == Path.separator && components.count > 1 { + let p = components.joined(separator: Path.separator) +#if os(Linux) + let index = p.startIndex.distanceTo(p.startIndex.successor()) + path = NSString(string: p).substringFromIndex(index) +#else + path = p.substring(from: p.startIndex.successor()) +#endif + + } else { + path = components.joined(separator: Path.separator) } - - #endif + } + + #endif } // MARK: StringLiteralConvertible extension Path : StringLiteralConvertible { - public typealias ExtendedGraphemeClusterLiteralType = StringLiteralType - public typealias UnicodeScalarLiteralType = StringLiteralType - - public init(extendedGraphemeClusterLiteral path: StringLiteralType) { - self.init(stringLiteral: path) - } - - public init(unicodeScalarLiteral path: StringLiteralType) { - self.init(stringLiteral: path) - } - - public init(stringLiteral value: StringLiteralType) { - self.path = value - } + public typealias ExtendedGraphemeClusterLiteralType = StringLiteralType + public typealias UnicodeScalarLiteralType = StringLiteralType + + public init(extendedGraphemeClusterLiteral path: StringLiteralType) { + self.init(stringLiteral: path) + } + + public init(unicodeScalarLiteral path: StringLiteralType) { + self.init(stringLiteral: path) + } + + public init(stringLiteral value: StringLiteralType) { + self.path = value + } } // MARK: CustomStringConvertible extension Path : CustomStringConvertible { - public var description: String { - return self.path - } + public var description: String { + return self.path + } } // MARK: Hashable extension Path : Hashable { - public var hashValue: Int { - return path.hashValue - } + public var hashValue: Int { + return path.hashValue + } } // MARK: Path Info extension Path { - /// Test whether a path is absolute. - /// - /// - Returns: `true` iff the path begings with a slash - /// - public var isAbsolute: Bool { - return path.hasPrefix(Path.separator) - } - - /// Test whether a path is relative. - /// - /// - Returns: `true` iff a path is relative (not absolute) - /// - public var isRelative: Bool { - return !isAbsolute - } - - /// Concatenates relative paths to the current directory and derives the normalized path - /// - /// - Returns: the absolute path in the actual filesystem - /// - public func absolute() -> Path { - if isAbsolute { - return normalize() - } - - return (Path.current + self).normalize() - } - - /// Normalizes the path, this cleans up redundant ".." and ".", double slashes - /// and resolves "~". - /// - /// - Returns: a new path made by removing extraneous path components from the underlying String - /// representation. - /// - public func normalize() -> Path { - #if !swift(>=3.0) - return Path(NSString(string: self.path).stringByStandardizingPath) - #else - return Path(NSString(string: self.path).standardizingPath) - #endif - } - - /// De-normalizes the path, by replacing the current user home directory with "~". - /// - /// - Returns: a new path made by removing extraneous path components from the underlying String - /// representation. - /// - public func abbreviate() -> Path { - #if os(Linux) - // TODO: actually de-normalize the path - return self - #else - #if !swift(>=3.0) - return Path(NSString(string: self.path).stringByAbbreviatingWithTildeInPath) - #else - return Path(NSString(string: self.path).abbreviatingWithTildeInPath) - #endif - #endif - } - - /// Returns the path of the item pointed to by a symbolic link. - /// - /// - Returns: the path of directory or file to which the symbolic link refers - /// - public func symlinkDestination() throws -> Path { - #if !swift(>=3.0) - let symlinkDestination = try Path.fileManager.destinationOfSymbolicLinkAtPath(path) - #else - let symlinkDestination = try Path.fileManager.destinationOfSymbolicLink(atPath:path) - #endif - let symlinkPath = Path(symlinkDestination) - if symlinkPath.isRelative { - return self + ".." + symlinkPath - } else { - return symlinkPath - } + /// Test whether a path is absolute. + /// + /// - Returns: `true` iff the path begings with a slash + /// + public var isAbsolute: Bool { + return path.hasPrefix(Path.separator) + } + + /// Test whether a path is relative. + /// + /// - Returns: `true` iff a path is relative (not absolute) + /// + public var isRelative: Bool { + return !isAbsolute + } + + /// Concatenates relative paths to the current directory and derives the normalized path + /// + /// - Returns: the absolute path in the actual filesystem + /// + public func absolute() -> Path { + if isAbsolute { + return normalize() + } + + return (Path.current + self).normalize() + } + + /// Normalizes the path, this cleans up redundant ".." and ".", double slashes + /// and resolves "~". + /// + /// - Returns: a new path made by removing extraneous path components from the underlying String + /// representation. + /// + public func normalize() -> Path { + #if swift(<3.0) + return Path(NSString(string: self.path).stringByStandardizingPath) + #else + return Path(NSString(string: self.path).standardizingPath) + #endif + } + + /// De-normalizes the path, by replacing the current user home directory with "~". + /// + /// - Returns: a new path made by removing extraneous path components from the underlying String + /// representation. + /// + public func abbreviate() -> Path { +#if os(Linux) + // TODO: actually de-normalize the path + return self +#else + #if swift(<3.0) + return Path(NSString(string: self.path).stringByAbbreviatingWithTildeInPath) + #else + return Path(NSString(string: self.path).abbreviatingWithTildeInPath) + #endif +#endif + } + + /// Returns the path of the item pointed to by a symbolic link. + /// + /// - Returns: the path of directory or file to which the symbolic link refers + /// + public func symlinkDestination() throws -> Path { + #if swift(<3.0) + let symlinkDestination = try Path.fileManager.destinationOfSymbolicLinkAtPath(path) + #else + let symlinkDestination = try Path.fileManager.destinationOfSymbolicLink(atPath:path) + #endif + let symlinkPath = Path(symlinkDestination) + if symlinkPath.isRelative { + return self + ".." + symlinkPath + } else { + return symlinkPath } + } } // MARK: Path Components extension Path { - /// The last path component - /// - /// - Returns: the last path component - /// - public var lastComponent: String { - return NSString(string: path).lastPathComponent - } - - /// The last path component without file extension - /// - /// - Note: This returns "." for "..". - /// - /// - Returns: the last path component without file extension - /// - public var lastComponentWithoutExtension: String { - #if !swift(>=3.0) - return NSString(string: lastComponent).stringByDeletingPathExtension - #else - return NSString(string: lastComponent).deletingPathExtension - #endif - } - - /// Splits the string representation on the directory separator. - /// Absolute paths remain the leading slash as first component. - /// - /// - Returns: all path components - /// - public var components: [String] { - return NSString(string: path).pathComponents - } - - /// The file extension behind the last dot of the last component. - /// - /// - Returns: the file extension - /// - public var `extension`: String? { - let pathExtension = NSString(string: path).pathExtension - if pathExtension.isEmpty { - return nil - } - - return pathExtension - } + /// The last path component + /// + /// - Returns: the last path component + /// + public var lastComponent: String { + return NSString(string: path).lastPathComponent + } + + /// The last path component without file extension + /// + /// - Note: This returns "." for "..". + /// + /// - Returns: the last path component without file extension + /// + public var lastComponentWithoutExtension: String { + #if swift(<3.0) + return NSString(string: lastComponent).stringByDeletingPathExtension + #else + return NSString(string: lastComponent).deletingPathExtension + #endif + } + + /// Splits the string representation on the directory separator. + /// Absolute paths remain the leading slash as first component. + /// + /// - Returns: all path components + /// + public var components: [String] { + return NSString(string: path).pathComponents + } + + /// The file extension behind the last dot of the last component. + /// + /// - Returns: the file extension + /// + public var `extension`: String? { + let pathExtension = NSString(string: path).pathExtension + if pathExtension.isEmpty { + return nil + } + + return pathExtension + } } // MARK: File Info extension Path { - /// Test whether a file or directory exists at a specified path - /// - /// - Returns: `false` iff the path doesn't exist on disk or its existence could not be - /// determined - /// - public var exists: Bool { - #if !swift(>=3.0) - return Path.fileManager.fileExistsAtPath(self.path) - #else - return Path.fileManager.fileExists(atPath:self.path) - #endif - } - - /// Test whether a path is a directory. - /// - /// - Returns: `true` if the path is a directory or a symbolic link that points to a directory; - /// `false` if the path is not a directory or the path doesn't exist on disk or its existence - /// could not be determined - /// - public var isDirectory: Bool { - var directory = ObjCBool(false) - #if !swift(>=3.0) - guard Path.fileManager.fileExistsAtPath(normalize().path, isDirectory: &directory) else { - return false - } - #else - guard Path.fileManager.fileExists(atPath: normalize().path, isDirectory: &directory) else { - return false - } - #endif - return directory.boolValue - } - - /// Test whether a path is a regular file. - /// - /// - Returns: `true` if the path is neither a directory nor a symbolic link that points to a - /// directory; `false` if the path is a directory or a symbolic link that points to a - /// directory or the path doesn't exist on disk or its existence - /// could not be determined - /// - public var isFile: Bool { - var directory = ObjCBool(false) - #if !swift(>=3.0) - guard Path.fileManager.fileExistsAtPath(normalize().path, isDirectory: &directory) else { - return false - } - #else - guard Path.fileManager.fileExists(atPath: normalize().path, isDirectory: &directory) else { - return false - } - #endif - return !directory.boolValue - } - - /// Test whether a path is a symbolic link. - /// - /// - Returns: `true` if the path is a symbolic link; `false` if the path doesn't exist on disk - /// or its existence could not be determined - /// - public var isSymlink: Bool { - do { - #if !swift(>=3.0) - let _ = try Path.fileManager.destinationOfSymbolicLinkAtPath(path) - #else - let _ = try Path.fileManager.destinationOfSymbolicLink(atPath: path) - #endif - return true - } catch { - return false - } - } - - /// Test whether a path is readable - /// - /// - Returns: `true` if the current process has read privileges for the file at path; - /// otherwise `false` if the process does not have read privileges or the existence of the - /// file could not be determined. - /// - public var isReadable: Bool { - #if !swift(>=3.0) - return Path.fileManager.isReadableFileAtPath(self.path) - #else - return Path.fileManager.isReadableFile(atPath: self.path) - #endif + /// Test whether a file or directory exists at a specified path + /// + /// - Returns: `false` iff the path doesn't exist on disk or its existence could not be + /// determined + /// + public var exists: Bool { + #if swift(<3.0) + return Path.fileManager.fileExistsAtPath(self.path) + #else + return Path.fileManager.fileExists(atPath:self.path) + #endif + } + + /// Test whether a path is a directory. + /// + /// - Returns: `true` if the path is a directory or a symbolic link that points to a directory; + /// `false` if the path is not a directory or the path doesn't exist on disk or its existence + /// could not be determined + /// + public var isDirectory: Bool { + var directory = ObjCBool(false) + #if swift(<3.0) + guard Path.fileManager.fileExistsAtPath(normalize().path, isDirectory: &directory) else { + return false } - - /// Test whether a path is writeable - /// - /// - Returns: `true` if the current process has write privileges for the file at path; - /// otherwise `false` if the process does not have write privileges or the existence of the - /// file could not be determined. - /// - public var isWritable: Bool { - #if !swift(>=3.0) - return Path.fileManager.isWritableFileAtPath(self.path) - #else - return Path.fileManager.isWritableFile(atPath: self.path) - #endif + #else + guard Path.fileManager.fileExists(atPath: normalize().path, isDirectory: &directory) else { + return false } - - /// Test whether a path is executable - /// - /// - Returns: `true` if the current process has execute privileges for the file at path; - /// otherwise `false` if the process does not have execute privileges or the existence of the - /// file could not be determined. - /// - public var isExecutable: Bool { - #if !swift(>=3.0) - return Path.fileManager.isExecutableFileAtPath(self.path) - #else - return Path.fileManager.isExecutableFile(atPath: self.path) - #endif + #endif + return directory.boolValue + } + + /// Test whether a path is a regular file. + /// + /// - Returns: `true` if the path is neither a directory nor a symbolic link that points to a + /// directory; `false` if the path is a directory or a symbolic link that points to a + /// directory or the path doesn't exist on disk or its existence + /// could not be determined + /// + public var isFile: Bool { + var directory = ObjCBool(false) + #if swift(<3.0) + guard Path.fileManager.fileExistsAtPath(normalize().path, isDirectory: &directory) else { + return false } - - /// Test whether a path is deletable - /// - /// - Returns: `true` if the current process has delete privileges for the file at path; - /// otherwise `false` if the process does not have delete privileges or the existence of the - /// file could not be determined. - /// - public var isDeletable: Bool { - #if !swift(>=3.0) - return Path.fileManager.isDeletableFileAtPath(self.path) - #else - return Path.fileManager.isDeletableFile(atPath: self.path) - #endif + #else + guard Path.fileManager.fileExists(atPath: normalize().path, isDirectory: &directory) else { + return false } + #endif + return !directory.boolValue + } + + /// Test whether a path is a symbolic link. + /// + /// - Returns: `true` if the path is a symbolic link; `false` if the path doesn't exist on disk + /// or its existence could not be determined + /// + public var isSymlink: Bool { + do { + #if swift(<3.0) + let _ = try Path.fileManager.destinationOfSymbolicLinkAtPath(path) + #else + let _ = try Path.fileManager.destinationOfSymbolicLink(atPath: path) + #endif + return true + } catch { + return false + } + } + + /// Test whether a path is readable + /// + /// - Returns: `true` if the current process has read privileges for the file at path; + /// otherwise `false` if the process does not have read privileges or the existence of the + /// file could not be determined. + /// + public var isReadable: Bool { + #if swift(<3.0) + return Path.fileManager.isReadableFileAtPath(self.path) + #else + return Path.fileManager.isReadableFile(atPath: self.path) + #endif + } + + /// Test whether a path is writeable + /// + /// - Returns: `true` if the current process has write privileges for the file at path; + /// otherwise `false` if the process does not have write privileges or the existence of the + /// file could not be determined. + /// + public var isWritable: Bool { + #if swift(<3.0) + return Path.fileManager.isWritableFileAtPath(self.path) + #else + return Path.fileManager.isWritableFile(atPath: self.path) + #endif + } + + /// Test whether a path is executable + /// + /// - Returns: `true` if the current process has execute privileges for the file at path; + /// otherwise `false` if the process does not have execute privileges or the existence of the + /// file could not be determined. + /// + public var isExecutable: Bool { + #if swift(<3.0) + return Path.fileManager.isExecutableFileAtPath(self.path) + #else + return Path.fileManager.isExecutableFile(atPath: self.path) + #endif + } + + /// Test whether a path is deletable + /// + /// - Returns: `true` if the current process has delete privileges for the file at path; + /// otherwise `false` if the process does not have delete privileges or the existence of the + /// file could not be determined. + /// + public var isDeletable: Bool { + #if swift(<3.0) + return Path.fileManager.isDeletableFileAtPath(self.path) + #else + return Path.fileManager.isDeletableFile(atPath: self.path) + #endif + } } // MARK: File Manipulation extension Path { - /// Create the directory. - /// - /// - Note: This method fails if any of the intermediate parent directories does not exist. - /// This method also fails if any of the intermediate path elements corresponds to a file and - /// not a directory. - /// - public func mkdir() throws -> () { - #if !swift(>=3.0) - try Path.fileManager.createDirectoryAtPath(self.path, withIntermediateDirectories: false, attributes: nil) - #else - try Path.fileManager.createDirectory(atPath: self.path, withIntermediateDirectories: false, attributes: nil) - #endif - } - - /// Create the directory and any intermediate parent directories that do not exist. - /// - /// - Note: This method fails if any of the intermediate path elements corresponds to a file and - /// not a directory. - /// - public func mkpath() throws -> () { - #if !swift(>=3.0) - try Path.fileManager.createDirectoryAtPath(self.path, withIntermediateDirectories: true, attributes: nil) - #else - try Path.fileManager.createDirectory(atPath: self.path, withIntermediateDirectories: true, attributes: nil) - #endif - } - - /// Delete the file or directory. - /// - /// - Note: If the path specifies a directory, the contents of that directory are recursively - /// removed. - /// - public func delete() throws -> () { - #if !swift(>=3.0) - try Path.fileManager.removeItemAtPath(self.path) - #else - try Path.fileManager.removeItem(atPath: self.path) - #endif - } - - /// Move the file or directory to a new location synchronously. - /// - /// - Parameter destination: The new path. This path must include the name of the file or - /// directory in its new location. - /// - public func move(destination: Path) throws -> () { - #if !swift(>=3.0) - try Path.fileManager.moveItemAtPath(self.path, toPath: destination.path) - #else - try Path.fileManager.moveItem(atPath: self.path, toPath: destination.path) - #endif - } - - /// Copy the file or directory to a new location synchronously. - /// - /// - Parameter destination: The new path. This path must include the name of the file or - /// directory in its new location. - /// - public func copy(destination: Path) throws -> () { - #if !swift(>=3.0) - try Path.fileManager.copyItemAtPath(self.path, toPath: destination.path) - #else - try Path.fileManager.copyItem(atPath: self.path, toPath: destination.path) - #endif - } - - /// Creates a hard link at a new destination. - /// - /// - Parameter destination: The location where the link will be created. - /// - public func link(destination: Path) throws -> () { - #if !swift(>=3.0) - try Path.fileManager.linkItemAtPath(self.path, toPath: destination.path) - #else - try Path.fileManager.linkItem(atPath: self.path, toPath: destination.path) - #endif - } - - /// Creates a symbolic link at a new destination. - /// - /// - Parameter destintation: The location where the link will be created. - /// - public func symlink(destination: Path) throws -> () { - #if !swift(>=3.0) - try Path.fileManager.createSymbolicLinkAtPath(self.path, withDestinationPath: destination.path) - #else - try Path.fileManager.createSymbolicLink(atPath: self.path, withDestinationPath: destination.path) - #endif - } + /// Create the directory. + /// + /// - Note: This method fails if any of the intermediate parent directories does not exist. + /// This method also fails if any of the intermediate path elements corresponds to a file and + /// not a directory. + /// + public func mkdir() throws -> () { + #if swift(<3.0) + try Path.fileManager.createDirectoryAtPath(self.path, withIntermediateDirectories: false, attributes: nil) + #else + try Path.fileManager.createDirectory(atPath: self.path, withIntermediateDirectories: false, attributes: nil) + #endif + } + + /// Create the directory and any intermediate parent directories that do not exist. + /// + /// - Note: This method fails if any of the intermediate path elements corresponds to a file and + /// not a directory. + /// + public func mkpath() throws -> () { + #if swift(<3.0) + try Path.fileManager.createDirectoryAtPath(self.path, withIntermediateDirectories: true, attributes: nil) + #else + try Path.fileManager.createDirectory(atPath: self.path, withIntermediateDirectories: true, attributes: nil) + #endif + } + + /// Delete the file or directory. + /// + /// - Note: If the path specifies a directory, the contents of that directory are recursively + /// removed. + /// + public func delete() throws -> () { + #if swift(<3.0) + try Path.fileManager.removeItemAtPath(self.path) + #else + try Path.fileManager.removeItem(atPath: self.path) + #endif + } + + /// Move the file or directory to a new location synchronously. + /// + /// - Parameter destination: The new path. This path must include the name of the file or + /// directory in its new location. + /// + public func move(destination: Path) throws -> () { + #if swift(<3.0) + try Path.fileManager.moveItemAtPath(self.path, toPath: destination.path) + #else + try Path.fileManager.moveItem(atPath: self.path, toPath: destination.path) + #endif + } + + /// Copy the file or directory to a new location synchronously. + /// + /// - Parameter destination: The new path. This path must include the name of the file or + /// directory in its new location. + /// + public func copy(destination: Path) throws -> () { + #if swift(<3.0) + try Path.fileManager.copyItemAtPath(self.path, toPath: destination.path) + #else + try Path.fileManager.copyItem(atPath: self.path, toPath: destination.path) + #endif + } + + /// Creates a hard link at a new destination. + /// + /// - Parameter destination: The location where the link will be created. + /// + public func link(destination: Path) throws -> () { + #if swift(<3.0) + try Path.fileManager.linkItemAtPath(self.path, toPath: destination.path) + #else + try Path.fileManager.linkItem(atPath: self.path, toPath: destination.path) + #endif + } + + /// Creates a symbolic link at a new destination. + /// + /// - Parameter destintation: The location where the link will be created. + /// + public func symlink(destination: Path) throws -> () { + #if swift(<3.0) + try Path.fileManager.createSymbolicLinkAtPath(self.path, withDestinationPath: destination.path) + #else + try Path.fileManager.createSymbolicLink(atPath: self.path, withDestinationPath: destination.path) + #endif + } } // MARK: Current Directory extension Path { - /// The current working directory of the process - /// - /// - Returns: the current working directory of the process - /// - public static var current: Path { - get { - return self.init(Path.fileManager.currentDirectoryPath) - } - set { - Path.fileManager.changeCurrentDirectoryPath(newValue.description) - } - } - - /// Changes the current working directory of the process to the path during the execution of the - /// given block. - /// - /// - Note: The original working directory is restored when the block returns or throws. - /// - Parameter closure: A closure to be executed while the current directory is configured to - /// the path. - /// - public func chdir(@noescape closure: () throws -> ()) rethrows { - let previous = Path.current - Path.current = self - defer { Path.current = previous } - try closure() - } + /// The current working directory of the process + /// + /// - Returns: the current working directory of the process + /// + public static var current: Path { + get { + return self.init(Path.fileManager.currentDirectoryPath) + } + set { + Path.fileManager.changeCurrentDirectoryPath(newValue.description) + } + } + + /// Changes the current working directory of the process to the path during the execution of the + /// given block. + /// + /// - Note: The original working directory is restored when the block returns or throws. + /// - Parameter closure: A closure to be executed while the current directory is configured to + /// the path. + /// + public func chdir(@noescape closure: () throws -> ()) rethrows { + let previous = Path.current + Path.current = self + defer { Path.current = previous } + try closure() + } } // MARK: Temporary extension Path { - /// - Returns: the path to either the user’s or application’s home directory, - /// depending on the platform. - /// - public static var home: Path { - #if os(Linux) - return Path(NSProcessInfo.processInfo().environment["HOME"] ?? "/") - #else - return Path(NSHomeDirectory()) - #endif - } - - /// - Returns: the path of the temporary directory for the current user. - /// - public static var temporary: Path { - #if os(Linux) - return Path(NSProcessInfo.processInfo().environment["TMP"] ?? "/tmp") - #else - return Path(NSTemporaryDirectory()) - #endif - } - - /// - Returns: the path of a temporary directory unique for the process. - /// - Note: Based on `NSProcessInfo.globallyUniqueString`. - /// - public static func processUniqueTemporary() throws -> Path { - let path = temporary + NSProcessInfo.processInfo().globallyUniqueString - if !path.exists { - try path.mkdir() - } - return path - } - - /// - Returns: the path of a temporary directory unique for each call. - /// - Note: Based on `NSUUID`. - /// - public static func uniqueTemporary() throws -> Path { - #if !swift(>=3.0) - let path = try processUniqueTemporary() + NSUUID().UUIDString - #else - let path = try processUniqueTemporary() + NSUUID().uuidString - #endif - try path.mkdir() - return path - } + /// - Returns: the path to either the user’s or application’s home directory, + /// depending on the platform. + /// + public static var home: Path { +#if os(Linux) + return Path(NSProcessInfo.processInfo().environment["HOME"] ?? "/") +#else + return Path(NSHomeDirectory()) +#endif + } + + /// - Returns: the path of the temporary directory for the current user. + /// + public static var temporary: Path { +#if os(Linux) + return Path(NSProcessInfo.processInfo().environment["TMP"] ?? "/tmp") +#else + return Path(NSTemporaryDirectory()) +#endif + } + + /// - Returns: the path of a temporary directory unique for the process. + /// - Note: Based on `NSProcessInfo.globallyUniqueString`. + /// + public static func processUniqueTemporary() throws -> Path { + let path = temporary + NSProcessInfo.processInfo().globallyUniqueString + if !path.exists { + try path.mkdir() + } + return path + } + + /// - Returns: the path of a temporary directory unique for each call. + /// - Note: Based on `NSUUID`. + /// + public static func uniqueTemporary() throws -> Path { + #if swift(<3.0) + let path = try processUniqueTemporary() + NSUUID().UUIDString + #else + let path = try processUniqueTemporary() + NSUUID().uuidString + #endif + try path.mkdir() + return path + } } // MARK: Contents extension Path { - /// Reads the file. - /// - /// - Returns: the contents of the file at the specified path. - /// - public func read() throws -> NSData { - return try NSData(contentsOfFile: path, options: NSDataReadingOptions(rawValue: 0)) - } - - /// Reads the file contents and encoded its bytes to string applying the given encoding. - /// - /// - Parameter encoding: the encoding which should be used to decode the data. - /// (by default: `NSUTF8StringEncoding`) - /// - /// - Returns: the contents of the file at the specified path as string. - /// - public func read(encoding: NSStringEncoding = NSUTF8StringEncoding) throws -> String { - #if !swift(>=3.0) - return try NSString(contentsOfFile: path, encoding: encoding).substringFromIndex(0) as String - #else - return try NSString(contentsOfFile: path, encoding: encoding).substring(from:0) as String - #endif - } - - /// Write a file. - /// - /// - Note: Works atomically: the data is written to a backup file, and then — assuming no - /// errors occur — the backup file is renamed to the name specified by path. - /// - /// - Parameter data: the contents to write to file. - /// - public func write(data: NSData) throws { - #if !swift(>=3.0) - try data.writeToFile(normalize().path, options: .DataWritingAtomic) - #else - try data.write(toFile:normalize().path, options: .dataWritingAtomic) - #endif - } - - /// Reads the file. - /// - /// - Note: Works atomically: the data is written to a backup file, and then — assuming no - /// errors occur — the backup file is renamed to the name specified by path. - /// - /// - Parameter string: the string to write to file. - /// - /// - Parameter encoding: the encoding which should be used to represent the string as bytes. - /// (by default: `NSUTF8StringEncoding`) - /// - /// - Returns: the contents of the file at the specified path as string. - /// - public func write(string: String, encoding: NSStringEncoding = NSUTF8StringEncoding) throws { - #if !swift(>=3.0) - try NSString(string: string).writeToFile(normalize().path, atomically: true, encoding: encoding) - #else - try NSString(string: string).write(toFile:normalize().path, atomically: true, encoding: encoding) - #endif - } + /// Reads the file. + /// + /// - Returns: the contents of the file at the specified path. + /// + public func read() throws -> NSData { + return try NSData(contentsOfFile: path, options: NSDataReadingOptions(rawValue: 0)) + } + + /// Reads the file contents and encoded its bytes to string applying the given encoding. + /// + /// - Parameter encoding: the encoding which should be used to decode the data. + /// (by default: `NSUTF8StringEncoding`) + /// + /// - Returns: the contents of the file at the specified path as string. + /// + public func read(encoding: NSStringEncoding = NSUTF8StringEncoding) throws -> String { + #if swift(<3.0) + return try NSString(contentsOfFile: path, encoding: encoding).substringFromIndex(0) as String + #else + return try NSString(contentsOfFile: path, encoding: encoding).substring(from:0) as String + #endif + } + + /// Write a file. + /// + /// - Note: Works atomically: the data is written to a backup file, and then — assuming no + /// errors occur — the backup file is renamed to the name specified by path. + /// + /// - Parameter data: the contents to write to file. + /// + public func write(data: NSData) throws { + #if swift(<3.0) + try data.writeToFile(normalize().path, options: .DataWritingAtomic) + #else + try data.write(toFile:normalize().path, options: .dataWritingAtomic) + #endif + } + + /// Reads the file. + /// + /// - Note: Works atomically: the data is written to a backup file, and then — assuming no + /// errors occur — the backup file is renamed to the name specified by path. + /// + /// - Parameter string: the string to write to file. + /// + /// - Parameter encoding: the encoding which should be used to represent the string as bytes. + /// (by default: `NSUTF8StringEncoding`) + /// + /// - Returns: the contents of the file at the specified path as string. + /// + public func write(string: String, encoding: NSStringEncoding = NSUTF8StringEncoding) throws { + #if swift(<3.0) + try NSString(string: string).writeToFile(normalize().path, atomically: true, encoding: encoding) + #else + try NSString(string: string).write(toFile:normalize().path, atomically: true, encoding: encoding) + #endif + } } // MARK: Traversing extension Path { - /// Get the parent directory - /// - /// - Returns: the normalized path of the parent directory - /// - public func parent() -> Path { - return self + ".." + /// Get the parent directory + /// + /// - Returns: the normalized path of the parent directory + /// + public func parent() -> Path { + return self + ".." + } + + /// Performs a shallow enumeration in a directory + /// + /// - Returns: paths to all files, directories and symbolic links contained in the directory + /// + public func children() throws -> [Path] { + #if swift(<3.0) + return try Path.fileManager.contentsOfDirectoryAtPath(path).map { + self + Path($0) } - - /// Performs a shallow enumeration in a directory - /// - /// - Returns: paths to all files, directories and symbolic links contained in the directory - /// - public func children() throws -> [Path] { - #if !swift(>=3.0) - return try Path.fileManager.contentsOfDirectoryAtPath(path).map { - self + Path($0) - } - #else - return try Path.fileManager.contentsOfDirectory(atPath:path).map { - self + Path($0) - } - #endif - + #else + return try Path.fileManager.contentsOfDirectory(atPath:path).map { + self + Path($0) + } + #endif + + } + + /// Performs a deep enumeration in a directory + /// + /// - Returns: paths to all files, directories and symbolic links contained in the directory or + /// any subdirectory. + /// + public func recursiveChildren() throws -> [Path] { + #if swift(<3.0) + return try Path.fileManager.subpathsOfDirectoryAtPath(path).map { + self + Path($0) } - - /// Performs a deep enumeration in a directory - /// - /// - Returns: paths to all files, directories and symbolic links contained in the directory or - /// any subdirectory. - /// - public func recursiveChildren() throws -> [Path] { - #if !swift(>=3.0) - return try Path.fileManager.subpathsOfDirectoryAtPath(path).map { - self + Path($0) - } - #else - return try Path.fileManager.subpathsOfDirectory(atPath:path).map { - self + Path($0) - } - #endif + #else + return try Path.fileManager.subpathsOfDirectory(atPath:path).map { + self + Path($0) } + #endif + } } // MARK: Globbing extension Path { - public static func glob(pattern: String) -> [Path] { - var gt = glob_t() - let cPattern = strdup(pattern) - defer { - globfree(>) - free(cPattern) - } - - let flags = GLOB_TILDE | GLOB_BRACE | GLOB_MARK - if system_glob(cPattern, flags, nil, >) == 0 { - #if os(Linux) - let matchc = gt.gl_pathc - #else - let matchc = gt.gl_matchc - #endif - #if !swift(>=3.0) - return (0.. [Path] { + var gt = glob_t() + let cPattern = strdup(pattern) + defer { + globfree(>) + free(cPattern) } - - public func glob(pattern: String) -> [Path] { - return Path.glob((self + pattern).description) + + let flags = GLOB_TILDE | GLOB_BRACE | GLOB_MARK + if system_glob(cPattern, flags, nil, >) == 0 { +#if os(Linux) + let matchc = gt.gl_pathc +#else + let matchc = gt.gl_matchc +#endif + #if swift(<3.0) + return (0.. [Path] { + return Path.glob((self + pattern).description) + } } // MARK: SequenceType extension Path : Sequence { - /// Enumerates the contents of a directory, returning the paths of all files and directories - /// contained within that directory. These paths are relative to the directory. - public struct DirectoryEnumerator : IteratorProtocol { - public typealias Element = Path - - let path: Path - let directoryEnumerator: NSDirectoryEnumerator - - init(path: Path) { - self.path = path - #if !swift(>=3.0) - self.directoryEnumerator = Path.fileManager.enumeratorAtPath(path.path)! - #else - self.directoryEnumerator = Path.fileManager.enumerator(atPath:path.path)! - #endif - } - - public func next() -> Path? { - if let next = directoryEnumerator.nextObject() as! String? { - return path + next - } - return nil - } - - /// Skip recursion into the most recently obtained subdirectory. - public func skipDescendants() { - directoryEnumerator.skipDescendants() - } - } - - /// Perform a deep enumeration of a directory. - /// - /// - Returns: a directory enumerator that can be used to perform a deep enumeration of the - /// directory. - /// - #if !swift(>=3.0) - public func generate() -> DirectoryEnumerator { + /// Enumerates the contents of a directory, returning the paths of all files and directories + /// contained within that directory. These paths are relative to the directory. + public struct DirectoryEnumerator : IteratorProtocol { + public typealias Element = Path + + let path: Path + let directoryEnumerator: NSDirectoryEnumerator + + init(path: Path) { + self.path = path + #if swift(<3.0) + self.directoryEnumerator = Path.fileManager.enumeratorAtPath(path.path)! + #else + self.directoryEnumerator = Path.fileManager.enumerator(atPath:path.path)! + #endif + } + + public func next() -> Path? { + if let next = directoryEnumerator.nextObject() as! String? { + return path + next + } + return nil + } + + /// Skip recursion into the most recently obtained subdirectory. + public func skipDescendants() { + directoryEnumerator.skipDescendants() + } + } + + /// Perform a deep enumeration of a directory. + /// + /// - Returns: a directory enumerator that can be used to perform a deep enumeration of the + /// directory. + /// + #if swift(<3.0) + public func generate() -> DirectoryEnumerator { return DirectoryEnumerator(path: self) - } - #else - public func makeIterator() -> DirectoryEnumerator { - return DirectoryEnumerator(path: self) - } - #endif + } + #else + public func makeIterator() -> DirectoryEnumerator { + return DirectoryEnumerator(path: self) + } + #endif } @@ -781,7 +778,7 @@ extension Path : Equatable {} /// ./foo.txt) can refer to the same file. /// public func ==(lhs: Path, rhs: Path) -> Bool { - return lhs.path == rhs.path + return lhs.path == rhs.path } @@ -794,8 +791,8 @@ public func ==(lhs: Path, rhs: Path) -> Bool { /// - the paths can be normalized to equal Paths. /// public func ~=(lhs: Path, rhs: Path) -> Bool { - return lhs == rhs - || lhs.normalize() == rhs.normalize() + return lhs == rhs + || lhs.normalize() == rhs.normalize() } @@ -805,7 +802,7 @@ extension Path : Comparable {} /// Defines a strict total order over Paths based on their underlying string representation. public func <(lhs: Path, rhs: Path) -> Bool { - return lhs.path < rhs.path + return lhs.path < rhs.path } @@ -813,58 +810,58 @@ public func <(lhs: Path, rhs: Path) -> Bool { /// Appends a Path fragment to another Path to produce a new Path public func +(lhs: Path, rhs: Path) -> Path { - return lhs.path + rhs.path + return lhs.path + rhs.path } /// Appends a String fragment to another Path to produce a new Path public func +(lhs: Path, rhs: String) -> Path { - return lhs.path + rhs + return lhs.path + rhs } /// Appends a String fragment to another String to produce a new Path internal func +(lhs: String, rhs: String) -> Path { - if rhs.hasPrefix(Path.separator) { - // Absolute paths replace relative paths - return Path(rhs) - } else { - var lSlice = NSString(string: lhs).pathComponents.fullSlice - var rSlice = NSString(string: rhs).pathComponents.fullSlice - - // Get rid of trailing "/" at the left side - if lSlice.count > 1 && lSlice.last == Path.separator { - lSlice.removeLast() - } - - // Advance after the first relevant "." - lSlice = lSlice.filter { $0 != "." }.fullSlice - rSlice = rSlice.filter { $0 != "." }.fullSlice - - // Eats up trailing components of the left and leading ".." of the right side - while lSlice.last != ".." && rSlice.first == ".." { - if (lSlice.count > 1 || lSlice.first != Path.separator) && !lSlice.isEmpty { - // A leading "/" is never popped - lSlice.removeLast() - } - if !rSlice.isEmpty { - rSlice.removeFirst() - } - - switch (lSlice.isEmpty, rSlice.isEmpty) { - case (true, _): - break - case (_, true): - break - default: - continue - } - } - - return Path(components: lSlice + rSlice) - } + if rhs.hasPrefix(Path.separator) { + // Absolute paths replace relative paths + return Path(rhs) + } else { + var lSlice = NSString(string: lhs).pathComponents.fullSlice + var rSlice = NSString(string: rhs).pathComponents.fullSlice + + // Get rid of trailing "/" at the left side + if lSlice.count > 1 && lSlice.last == Path.separator { + lSlice.removeLast() + } + + // Advance after the first relevant "." + lSlice = lSlice.filter { $0 != "." }.fullSlice + rSlice = rSlice.filter { $0 != "." }.fullSlice + + // Eats up trailing components of the left and leading ".." of the right side + while lSlice.last != ".." && rSlice.first == ".." { + if (lSlice.count > 1 || lSlice.first != Path.separator) && !lSlice.isEmpty { + // A leading "/" is never popped + lSlice.removeLast() + } + if !rSlice.isEmpty { + rSlice.removeFirst() + } + + switch (lSlice.isEmpty, rSlice.isEmpty) { + case (true, _): + break + case (_, true): + break + default: + continue + } + } + + return Path(components: lSlice + rSlice) + } } extension Array { - var fullSlice: ArraySlice { - return self[0.. { + return self[0.. Date: Thu, 31 Mar 2016 22:29:00 +0200 Subject: [PATCH 4/5] Reverted illegal swift(<3.0) to !swift(>=3.0) in macros. --- Sources/PathKit.swift | 60 +++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Sources/PathKit.swift b/Sources/PathKit.swift index 138bbd8..7666e11 100644 --- a/Sources/PathKit.swift +++ b/Sources/PathKit.swift @@ -12,7 +12,7 @@ let system_glob = Darwin.glob import Foundation -#if swift(<3.0) +#if !swift(>=3.0) typealias Collection = CollectionType typealias Sequence = SequenceType typealias IteratorProtocol = GeneratorType @@ -41,7 +41,7 @@ public struct Path { } /// Create a Path by joining multiple path components together - #if swift(<3.0) + #if !swift(>=3.0) public init(components: S) { if components.isEmpty { path = "." @@ -155,7 +155,7 @@ extension Path { /// representation. /// public func normalize() -> Path { - #if swift(<3.0) + #if !swift(>=3.0) return Path(NSString(string: self.path).stringByStandardizingPath) #else return Path(NSString(string: self.path).standardizingPath) @@ -172,7 +172,7 @@ extension Path { // TODO: actually de-normalize the path return self #else - #if swift(<3.0) + #if !swift(>=3.0) return Path(NSString(string: self.path).stringByAbbreviatingWithTildeInPath) #else return Path(NSString(string: self.path).abbreviatingWithTildeInPath) @@ -185,7 +185,7 @@ extension Path { /// - Returns: the path of directory or file to which the symbolic link refers /// public func symlinkDestination() throws -> Path { - #if swift(<3.0) + #if !swift(>=3.0) let symlinkDestination = try Path.fileManager.destinationOfSymbolicLinkAtPath(path) #else let symlinkDestination = try Path.fileManager.destinationOfSymbolicLink(atPath:path) @@ -218,7 +218,7 @@ extension Path { /// - Returns: the last path component without file extension /// public var lastComponentWithoutExtension: String { - #if swift(<3.0) + #if !swift(>=3.0) return NSString(string: lastComponent).stringByDeletingPathExtension #else return NSString(string: lastComponent).deletingPathExtension @@ -258,7 +258,7 @@ extension Path { /// determined /// public var exists: Bool { - #if swift(<3.0) + #if !swift(>=3.0) return Path.fileManager.fileExistsAtPath(self.path) #else return Path.fileManager.fileExists(atPath:self.path) @@ -273,7 +273,7 @@ extension Path { /// public var isDirectory: Bool { var directory = ObjCBool(false) - #if swift(<3.0) + #if !swift(>=3.0) guard Path.fileManager.fileExistsAtPath(normalize().path, isDirectory: &directory) else { return false } @@ -294,7 +294,7 @@ extension Path { /// public var isFile: Bool { var directory = ObjCBool(false) - #if swift(<3.0) + #if !swift(>=3.0) guard Path.fileManager.fileExistsAtPath(normalize().path, isDirectory: &directory) else { return false } @@ -313,7 +313,7 @@ extension Path { /// public var isSymlink: Bool { do { - #if swift(<3.0) + #if !swift(>=3.0) let _ = try Path.fileManager.destinationOfSymbolicLinkAtPath(path) #else let _ = try Path.fileManager.destinationOfSymbolicLink(atPath: path) @@ -331,7 +331,7 @@ extension Path { /// file could not be determined. /// public var isReadable: Bool { - #if swift(<3.0) + #if !swift(>=3.0) return Path.fileManager.isReadableFileAtPath(self.path) #else return Path.fileManager.isReadableFile(atPath: self.path) @@ -345,7 +345,7 @@ extension Path { /// file could not be determined. /// public var isWritable: Bool { - #if swift(<3.0) + #if !swift(>=3.0) return Path.fileManager.isWritableFileAtPath(self.path) #else return Path.fileManager.isWritableFile(atPath: self.path) @@ -359,7 +359,7 @@ extension Path { /// file could not be determined. /// public var isExecutable: Bool { - #if swift(<3.0) + #if !swift(>=3.0) return Path.fileManager.isExecutableFileAtPath(self.path) #else return Path.fileManager.isExecutableFile(atPath: self.path) @@ -373,7 +373,7 @@ extension Path { /// file could not be determined. /// public var isDeletable: Bool { - #if swift(<3.0) + #if !swift(>=3.0) return Path.fileManager.isDeletableFileAtPath(self.path) #else return Path.fileManager.isDeletableFile(atPath: self.path) @@ -392,7 +392,7 @@ extension Path { /// not a directory. /// public func mkdir() throws -> () { - #if swift(<3.0) + #if !swift(>=3.0) try Path.fileManager.createDirectoryAtPath(self.path, withIntermediateDirectories: false, attributes: nil) #else try Path.fileManager.createDirectory(atPath: self.path, withIntermediateDirectories: false, attributes: nil) @@ -405,7 +405,7 @@ extension Path { /// not a directory. /// public func mkpath() throws -> () { - #if swift(<3.0) + #if !swift(>=3.0) try Path.fileManager.createDirectoryAtPath(self.path, withIntermediateDirectories: true, attributes: nil) #else try Path.fileManager.createDirectory(atPath: self.path, withIntermediateDirectories: true, attributes: nil) @@ -418,7 +418,7 @@ extension Path { /// removed. /// public func delete() throws -> () { - #if swift(<3.0) + #if !swift(>=3.0) try Path.fileManager.removeItemAtPath(self.path) #else try Path.fileManager.removeItem(atPath: self.path) @@ -431,7 +431,7 @@ extension Path { /// directory in its new location. /// public func move(destination: Path) throws -> () { - #if swift(<3.0) + #if !swift(>=3.0) try Path.fileManager.moveItemAtPath(self.path, toPath: destination.path) #else try Path.fileManager.moveItem(atPath: self.path, toPath: destination.path) @@ -444,7 +444,7 @@ extension Path { /// directory in its new location. /// public func copy(destination: Path) throws -> () { - #if swift(<3.0) + #if !swift(>=3.0) try Path.fileManager.copyItemAtPath(self.path, toPath: destination.path) #else try Path.fileManager.copyItem(atPath: self.path, toPath: destination.path) @@ -456,7 +456,7 @@ extension Path { /// - Parameter destination: The location where the link will be created. /// public func link(destination: Path) throws -> () { - #if swift(<3.0) + #if !swift(>=3.0) try Path.fileManager.linkItemAtPath(self.path, toPath: destination.path) #else try Path.fileManager.linkItem(atPath: self.path, toPath: destination.path) @@ -468,7 +468,7 @@ extension Path { /// - Parameter destintation: The location where the link will be created. /// public func symlink(destination: Path) throws -> () { - #if swift(<3.0) + #if !swift(>=3.0) try Path.fileManager.createSymbolicLinkAtPath(self.path, withDestinationPath: destination.path) #else try Path.fileManager.createSymbolicLink(atPath: self.path, withDestinationPath: destination.path) @@ -548,7 +548,7 @@ extension Path { /// - Note: Based on `NSUUID`. /// public static func uniqueTemporary() throws -> Path { - #if swift(<3.0) + #if !swift(>=3.0) let path = try processUniqueTemporary() + NSUUID().UUIDString #else let path = try processUniqueTemporary() + NSUUID().uuidString @@ -578,7 +578,7 @@ extension Path { /// - Returns: the contents of the file at the specified path as string. /// public func read(encoding: NSStringEncoding = NSUTF8StringEncoding) throws -> String { - #if swift(<3.0) + #if !swift(>=3.0) return try NSString(contentsOfFile: path, encoding: encoding).substringFromIndex(0) as String #else return try NSString(contentsOfFile: path, encoding: encoding).substring(from:0) as String @@ -593,7 +593,7 @@ extension Path { /// - Parameter data: the contents to write to file. /// public func write(data: NSData) throws { - #if swift(<3.0) + #if !swift(>=3.0) try data.writeToFile(normalize().path, options: .DataWritingAtomic) #else try data.write(toFile:normalize().path, options: .dataWritingAtomic) @@ -613,7 +613,7 @@ extension Path { /// - Returns: the contents of the file at the specified path as string. /// public func write(string: String, encoding: NSStringEncoding = NSUTF8StringEncoding) throws { - #if swift(<3.0) + #if !swift(>=3.0) try NSString(string: string).writeToFile(normalize().path, atomically: true, encoding: encoding) #else try NSString(string: string).write(toFile:normalize().path, atomically: true, encoding: encoding) @@ -638,7 +638,7 @@ extension Path { /// - Returns: paths to all files, directories and symbolic links contained in the directory /// public func children() throws -> [Path] { - #if swift(<3.0) + #if !swift(>=3.0) return try Path.fileManager.contentsOfDirectoryAtPath(path).map { self + Path($0) } @@ -656,7 +656,7 @@ extension Path { /// any subdirectory. /// public func recursiveChildren() throws -> [Path] { - #if swift(<3.0) + #if !swift(>=3.0) return try Path.fileManager.subpathsOfDirectoryAtPath(path).map { self + Path($0) } @@ -687,7 +687,7 @@ extension Path { #else let matchc = gt.gl_matchc #endif - #if swift(<3.0) + #if !swift(>=3.0) return (0..=3.0) self.directoryEnumerator = Path.fileManager.enumeratorAtPath(path.path)! #else self.directoryEnumerator = Path.fileManager.enumerator(atPath:path.path)! @@ -754,7 +754,7 @@ extension Path : Sequence { /// - Returns: a directory enumerator that can be used to perform a deep enumeration of the /// directory. /// - #if swift(<3.0) + #if !swift(>=3.0) public func generate() -> DirectoryEnumerator { return DirectoryEnumerator(path: self) } From 25a2ff15938a96edbe16bf25a40ffb95a1993596 Mon Sep 17 00:00:00 2001 From: Alex Tran Qui Date: Mon, 4 Apr 2016 13:27:25 +0200 Subject: [PATCH 5/5] Fixed compilation issues for Linux with DEVELOPMENT-SNAPSHOT-2016-03-24-a. The issues are due to Foundation not having been updated to the same level on the Linux platform. --- Sources/PathKit.swift | 176 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 142 insertions(+), 34 deletions(-) diff --git a/Sources/PathKit.swift b/Sources/PathKit.swift index 7666e11..38d8ec5 100644 --- a/Sources/PathKit.swift +++ b/Sources/PathKit.swift @@ -65,7 +65,7 @@ public struct Path { } else if components.first == Path.separator && components.count > 1 { let p = components.joined(separator: Path.separator) #if os(Linux) - let index = p.startIndex.distanceTo(p.startIndex.successor()) + let index = p.startIndex.distance( to: p.startIndex.successor()) path = NSString(string: p).substringFromIndex(index) #else path = p.substring(from: p.startIndex.successor()) @@ -158,7 +158,11 @@ extension Path { #if !swift(>=3.0) return Path(NSString(string: self.path).stringByStandardizingPath) #else - return Path(NSString(string: self.path).standardizingPath) + #if os(Linux) + return Path(NSString(string: self.path).stringByStandardizingPath) + #else + return Path(NSString(string: self.path).standardizingPath) + #endif #endif } @@ -188,7 +192,11 @@ extension Path { #if !swift(>=3.0) let symlinkDestination = try Path.fileManager.destinationOfSymbolicLinkAtPath(path) #else - let symlinkDestination = try Path.fileManager.destinationOfSymbolicLink(atPath:path) + #if os(Linux) + let symlinkDestination = try Path.fileManager.destinationOfSymbolicLinkAtPath(path) + #else + let symlinkDestination = try Path.fileManager.destinationOfSymbolicLink(atPath:path) + #endif #endif let symlinkPath = Path(symlinkDestination) if symlinkPath.isRelative { @@ -221,7 +229,11 @@ extension Path { #if !swift(>=3.0) return NSString(string: lastComponent).stringByDeletingPathExtension #else - return NSString(string: lastComponent).deletingPathExtension + #if os(Linux) + return NSString(string: lastComponent).stringByDeletingPathExtension + #else + return NSString(string: lastComponent).deletingPathExtension + #endif #endif } @@ -261,7 +273,11 @@ extension Path { #if !swift(>=3.0) return Path.fileManager.fileExistsAtPath(self.path) #else - return Path.fileManager.fileExists(atPath:self.path) + #if os(Linux) + return Path.fileManager.fileExistsAtPath(self.path) + #else + return Path.fileManager.fileExists(atPath:self.path) + #endif #endif } @@ -278,9 +294,15 @@ extension Path { return false } #else - guard Path.fileManager.fileExists(atPath: normalize().path, isDirectory: &directory) else { - return false - } + #if os(Linux) + guard Path.fileManager.fileExistsAtPath(normalize().path, isDirectory: &directory) else { + return false + } + #else + guard Path.fileManager.fileExists(atPath: normalize().path, isDirectory: &directory) else { + return false + } + #endif #endif return directory.boolValue } @@ -299,9 +321,15 @@ extension Path { return false } #else - guard Path.fileManager.fileExists(atPath: normalize().path, isDirectory: &directory) else { - return false - } + #if os(Linux) + guard Path.fileManager.fileExistsAtPath(normalize().path, isDirectory: &directory) else { + return false + } + #else + guard Path.fileManager.fileExists(atPath: normalize().path, isDirectory: &directory) else { + return false + } + #endif #endif return !directory.boolValue } @@ -316,7 +344,11 @@ extension Path { #if !swift(>=3.0) let _ = try Path.fileManager.destinationOfSymbolicLinkAtPath(path) #else - let _ = try Path.fileManager.destinationOfSymbolicLink(atPath: path) + #if os(Linux) + let _ = try Path.fileManager.destinationOfSymbolicLinkAtPath(path) + #else + let _ = try Path.fileManager.destinationOfSymbolicLink(atPath: path) + #endif #endif return true } catch { @@ -334,7 +366,11 @@ extension Path { #if !swift(>=3.0) return Path.fileManager.isReadableFileAtPath(self.path) #else - return Path.fileManager.isReadableFile(atPath: self.path) + #if os(Linux) + return Path.fileManager.isReadableFileAtPath(self.path) + #else + return Path.fileManager.isReadableFile(atPath: self.path) + #endif #endif } @@ -348,7 +384,11 @@ extension Path { #if !swift(>=3.0) return Path.fileManager.isWritableFileAtPath(self.path) #else - return Path.fileManager.isWritableFile(atPath: self.path) + #if os(Linux) + return Path.fileManager.isWritableFileAtPath(self.path) + #else + return Path.fileManager.isWritableFile(atPath: self.path) + #endif #endif } @@ -362,7 +402,11 @@ extension Path { #if !swift(>=3.0) return Path.fileManager.isExecutableFileAtPath(self.path) #else - return Path.fileManager.isExecutableFile(atPath: self.path) + #if os(Linux) + return Path.fileManager.isExecutableFileAtPath(self.path) + #else + return Path.fileManager.isExecutableFile(atPath: self.path) + #endif #endif } @@ -376,7 +420,11 @@ extension Path { #if !swift(>=3.0) return Path.fileManager.isDeletableFileAtPath(self.path) #else - return Path.fileManager.isDeletableFile(atPath: self.path) + #if os(Linux) + return Path.fileManager.isDeletableFileAtPath(self.path) + #else + return Path.fileManager.isDeletableFile(atPath: self.path) + #endif #endif } } @@ -395,7 +443,11 @@ extension Path { #if !swift(>=3.0) try Path.fileManager.createDirectoryAtPath(self.path, withIntermediateDirectories: false, attributes: nil) #else - try Path.fileManager.createDirectory(atPath: self.path, withIntermediateDirectories: false, attributes: nil) + #if os(Linux) + try Path.fileManager.createDirectoryAtPath(self.path, withIntermediateDirectories: false, attributes: nil) + #else + try Path.fileManager.createDirectory(atPath: self.path, withIntermediateDirectories: false, attributes: nil) + #endif #endif } @@ -408,7 +460,11 @@ extension Path { #if !swift(>=3.0) try Path.fileManager.createDirectoryAtPath(self.path, withIntermediateDirectories: true, attributes: nil) #else - try Path.fileManager.createDirectory(atPath: self.path, withIntermediateDirectories: true, attributes: nil) + #if os(Linux) + try Path.fileManager.createDirectoryAtPath(self.path, withIntermediateDirectories: true, attributes: nil) + #else + try Path.fileManager.createDirectory(atPath: self.path, withIntermediateDirectories: true, attributes: nil) + #endif #endif } @@ -421,7 +477,11 @@ extension Path { #if !swift(>=3.0) try Path.fileManager.removeItemAtPath(self.path) #else - try Path.fileManager.removeItem(atPath: self.path) + #if os(Linux) + try Path.fileManager.removeItemAtPath(self.path) + #else + try Path.fileManager.removeItem(atPath: self.path) + #endif #endif } @@ -434,7 +494,11 @@ extension Path { #if !swift(>=3.0) try Path.fileManager.moveItemAtPath(self.path, toPath: destination.path) #else - try Path.fileManager.moveItem(atPath: self.path, toPath: destination.path) + #if os(Linux) + try Path.fileManager.moveItemAtPath(self.path, toPath: destination.path) + #else + try Path.fileManager.moveItem(atPath: self.path, toPath: destination.path) + #endif #endif } @@ -447,7 +511,11 @@ extension Path { #if !swift(>=3.0) try Path.fileManager.copyItemAtPath(self.path, toPath: destination.path) #else - try Path.fileManager.copyItem(atPath: self.path, toPath: destination.path) + #if os(Linux) + try Path.fileManager.copyItemAtPath(self.path, toPath: destination.path) + #else + try Path.fileManager.copyItem(atPath: self.path, toPath: destination.path) + #endif #endif } @@ -459,7 +527,11 @@ extension Path { #if !swift(>=3.0) try Path.fileManager.linkItemAtPath(self.path, toPath: destination.path) #else - try Path.fileManager.linkItem(atPath: self.path, toPath: destination.path) + #if os(Linux) + try Path.fileManager.linkItemAtPath(self.path, toPath: destination.path) + #else + try Path.fileManager.linkItem(atPath: self.path, toPath: destination.path) + #endif #endif } @@ -471,7 +543,11 @@ extension Path { #if !swift(>=3.0) try Path.fileManager.createSymbolicLinkAtPath(self.path, withDestinationPath: destination.path) #else - try Path.fileManager.createSymbolicLink(atPath: self.path, withDestinationPath: destination.path) + #if os(Linux) + try Path.fileManager.createSymbolicLinkAtPath(self.path, withDestinationPath: destination.path) + #else + try Path.fileManager.createSymbolicLink(atPath: self.path, withDestinationPath: destination.path) + #endif #endif } } @@ -551,7 +627,11 @@ extension Path { #if !swift(>=3.0) let path = try processUniqueTemporary() + NSUUID().UUIDString #else - let path = try processUniqueTemporary() + NSUUID().uuidString + #if os(Linux) + let path = try processUniqueTemporary() + NSUUID().UUIDString + #else + let path = try processUniqueTemporary() + NSUUID().uuidString + #endif #endif try path.mkdir() return path @@ -581,7 +661,11 @@ extension Path { #if !swift(>=3.0) return try NSString(contentsOfFile: path, encoding: encoding).substringFromIndex(0) as String #else - return try NSString(contentsOfFile: path, encoding: encoding).substring(from:0) as String + #if os(Linux) + return try NSString(contentsOfFile: path, encoding: encoding).substringFromIndex(0) as String + #else + return try NSString(contentsOfFile: path, encoding: encoding).substring(from:0) as String + #endif #endif } @@ -596,7 +680,11 @@ extension Path { #if !swift(>=3.0) try data.writeToFile(normalize().path, options: .DataWritingAtomic) #else - try data.write(toFile:normalize().path, options: .dataWritingAtomic) + #if os(Linux) + try data.writeToFile(normalize().path, options: .DataWritingAtomic) + #else + try data.write(toFile:normalize().path, options: .dataWritingAtomic) + #endif #endif } @@ -616,7 +704,11 @@ extension Path { #if !swift(>=3.0) try NSString(string: string).writeToFile(normalize().path, atomically: true, encoding: encoding) #else - try NSString(string: string).write(toFile:normalize().path, atomically: true, encoding: encoding) + #if os(Linux) + try NSString(string: string).writeToFile(normalize().path, atomically: true, encoding: encoding) + #else + try NSString(string: string).write(toFile:normalize().path, atomically: true, encoding: encoding) + #endif #endif } } @@ -643,9 +735,15 @@ extension Path { self + Path($0) } #else - return try Path.fileManager.contentsOfDirectory(atPath:path).map { - self + Path($0) - } + #if os(Linux) + return try Path.fileManager.contentsOfDirectoryAtPath(path).map { + self + Path($0) + } + #else + return try Path.fileManager.contentsOfDirectory(atPath:path).map { + self + Path($0) + } + #endif #endif } @@ -661,9 +759,15 @@ extension Path { self + Path($0) } #else - return try Path.fileManager.subpathsOfDirectory(atPath:path).map { - self + Path($0) - } + #if os(Linux) + return try Path.fileManager.subpathsOfDirectoryAtPath(path).map { + self + Path($0) + } + #else + return try Path.fileManager.subpathsOfDirectory(atPath:path).map { + self + Path($0) + } + #endif #endif } } @@ -732,7 +836,11 @@ extension Path : Sequence { #if !swift(>=3.0) self.directoryEnumerator = Path.fileManager.enumeratorAtPath(path.path)! #else - self.directoryEnumerator = Path.fileManager.enumerator(atPath:path.path)! + #if os(Linux) + self.directoryEnumerator = Path.fileManager.enumeratorAtPath(path.path)! + #else + self.directoryEnumerator = Path.fileManager.enumerator(atPath:path.path)! + #endif #endif }