Skip to content

PackagePlugin: make Path a wrapper around AbsolutePath #5817

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ let package = Package(
// bootstrap scripts build the deployable version.
.target(
name: "PackagePlugin",
dependencies: [
.product(name: "TSCBasic", package: "swift-tools-support-core"),
],
exclude: ["CMakeLists.txt"],
swiftSettings: [
.unsafeFlags(["-package-description-version", "999.0"]),
Expand Down
3 changes: 3 additions & 0 deletions Sources/PackagePlugin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ set_target_properties(PackagePlugin PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/pm/PluginAPI
)

target_link_libraries(PackagePlugin PRIVATE
TSCBasic)

if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin)
target_link_libraries(PackagePlugin PRIVATE
Foundation)
Expand Down
72 changes: 14 additions & 58 deletions Sources/PackagePlugin/Path.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,102 +10,58 @@
//
//===----------------------------------------------------------------------===//

@_implementationOnly
import struct TSCBasic.AbsolutePath

/// A simple representation of a path in the file system.
public struct Path: Hashable {
private let _string: String
private let _storage: AbsolutePath

/// Initializes the path from the contents a string, which should be an
/// absolute path in platform representation.
public init(_ string: String) {
self._string = string
self._storage = AbsolutePath(string)
}

/// A string representation of the path.
public var string: String {
return _string
return self._storage.pathString
}

/// The last path component (including any extension).
public var lastComponent: String {
// Check for a special case of the root directory.
if _string == "/" {
// Root directory, so the basename is a single path separator (the
// root directory is special in this regard).
return "/"
}
// Find the last path separator.
guard let idx = _string.lastIndex(of: "/") else {
// No path separators, so the basename is the whole string.
return _string
}
// Otherwise, it's the string from (but not including) the last path
// separator.
return String(_string.suffix(from: _string.index(after: idx)))
return _storage.basename
}

/// The last path component (without any extension).
public var stem: String {
let filename = self.lastComponent
if let ext = self.extension {
return String(filename.dropLast(ext.count + 1))
} else {
return filename
}
return _storage.basenameWithoutExt
}

/// The filename extension, if any (without any leading dot).
public var `extension`: String? {
// Find the last path separator, if any.
let sIdx = _string.lastIndex(of: "/")

// Find the start of the basename.
let bIdx = (sIdx != nil) ? _string.index(after: sIdx!) : _string.startIndex

// Find the last `.` (if any), starting from the second character of
// the basename (a leading `.` does not make the whole path component
// a suffix).
let fIdx = _string.index(bIdx, offsetBy: 1, limitedBy: _string.endIndex) ?? _string.startIndex
if let idx = _string[fIdx...].lastIndex(of: ".") {
// Unless it's just a `.` at the end, we have found a suffix.
if _string.distance(from: idx, to: _string.endIndex) > 1 {
return String(_string.suffix(from: _string.index(idx, offsetBy: 1)))
}
}
// If we get this far, there is no suffix.
return nil
return _storage.extension
}

/// The path except for the last path component.
public func removingLastComponent() -> Path {
// Find the last path separator.
guard let idx = string.lastIndex(of: "/") else {
// No path separators, so the directory name is `.`.
return Path(".")
}
// Check if it's the only one in the string.
if idx == string.startIndex {
// Just one path separator, so the directory name is `/`.
return Path("/")
}
// Otherwise, it's the string up to (but not including) the last path
// separator.
return Path(String(_string.prefix(upTo: idx)))
return Path(_storage.dirname)
}

/// The result of appending a subpath, which should be a relative path in
/// platform representation.
public func appending(subpath: String) -> Path {
return Path(_string + (_string.hasSuffix("/") ? "" : "/") + subpath)
return Path(_storage.appending(component: subpath).pathString)
}

/// The result of appending one or more path components.
public func appending(_ components: [String]) -> Path {
return self.appending(subpath: components.joined(separator: "/"))
return Path(_storage.appending(components: components).pathString)
}

/// The result of appending one or more path components.
public func appending(_ components: String...) -> Path {
return self.appending(components)
return Path(_storage.appending(components: components).pathString)
}
}

Expand Down