Skip to content

Commit

Permalink
Specify isDirectory parameter when creating/modifying URLs
Browse files Browse the repository at this point in the history
Add missing `isDirectory` values in `appendingPathComponent` use

URL can perform disk access to determine if the given path component
points to a directory if this value is not specified so it can become
a performance issue.
  • Loading branch information
ethan-kusters committed May 22, 2022
1 parent 720e6a8 commit 7ce996e
Show file tree
Hide file tree
Showing 13 changed files with 66 additions and 22 deletions.
4 changes: 2 additions & 2 deletions Sources/SwiftDocC/Indexing/Navigator/NavigatorIndex.swift
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ public class NavigatorIndex {
let information = try environment.openDatabase(named: "information", flags: [])
self.information = information

let data = try Data(contentsOf: url.appendingPathComponent("availability.index"))
let data = try Data(contentsOf: url.appendingPathComponent("availability.index", isDirectory: false))
let plistDecoder = PropertyListDecoder()
let availabilityIndex = try plistDecoder.decode(AvailabilityIndex.self, from: data)
self.availabilityIndex = availabilityIndex
Expand All @@ -170,7 +170,7 @@ public class NavigatorIndex {
self.pathHasher = PathHasher(rawValue: information.get(type: String.self, forKey: NavigatorIndex.pathHasherKey) ?? "") ?? .fnv1

if readNavigatorTree {
self.navigatorTree = try NavigatorTree.read(from: url.appendingPathComponent("navigator.index"), bundleIdentifier: self.bundleIdentifier, interfaceLanguages: availabilityIndex.interfaceLanguages, presentationIdentifier: presentationIdentifier)
self.navigatorTree = try NavigatorTree.read(from: url.appendingPathComponent("navigator.index", isDirectory: false), bundleIdentifier: self.bundleIdentifier, interfaceLanguages: availabilityIndex.interfaceLanguages, presentationIdentifier: presentationIdentifier)
} else {
self.navigatorTree = NavigatorTree()
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftDocC/Indexing/Navigator/NavigatorTree.swift
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ public class NavigatorTree {

/// Read a tree by loading the whole data into disk and then process the content.
fileprivate static func __readAtomically(from path: String, bundleIdentifier: String? = nil, interfaceLanguageMap: [InterfaceLanguage.ID: InterfaceLanguage], presentationIdentifier: String? = nil) throws -> NavigatorTree {
let fileUrl = URL(fileURLWithPath: path)
let fileUrl = URL(fileURLWithPath: path, isDirectory: false)
let data = try Data(contentsOf: fileUrl)

var map = [UInt32: Node]()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,13 +118,15 @@ struct DataAssetManager {
for dataURL in datas {
let meta = try referenceMetaInformationForDataURL(dataURL, dataProvider: dataProvider, bundle: documentationBundle)

let referenceURL = URL(fileURLWithPath: meta.reference, isDirectory: false)

// Store the image with given scale information and display scale.
let name = URL(fileURLWithPath: meta.reference).lastPathComponent
let name = referenceURL.lastPathComponent
storage[name, default: DataAsset()]
.register(dataURL, with: meta.traits)

if name.contains(".") {
let nameNoExtension = URL(fileURLWithPath: name).deletingPathExtension().lastPathComponent
let nameNoExtension = referenceURL.deletingPathExtension().lastPathComponent
fuzzyKeyIndex[nameNoExtension] = name
}
}
Expand Down
51 changes: 44 additions & 7 deletions Sources/SwiftDocC/Infrastructure/NodeURLGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,56 @@ public struct NodeURLGenerator {
switch self {
case .documentation(let path):
// Format: "/documentation/MyKit/MyClass/myFunction(_:)"
return Self.documentationFolderURL.appendingPathComponent(urlReadablePath(path.removingLeadingSlash)).path
return Self.documentationFolderURL
.appendingPathComponent(
urlReadablePath(path.removingLeadingSlash),
isDirectory: false
)
.path
case .documentationCuration(let parentPath, let name):
// Format: "/documentation/MyKit/MyClass/MyCollection"
return Self.rootURL.appendingPathComponent(urlReadablePath(parentPath.removingLeadingSlash)).appendingPathComponent(urlReadablePath(name)).path
return Self.rootURL
.appendingPathComponent(
urlReadablePath(parentPath.removingLeadingSlash),
isDirectory: false
)
.appendingPathComponent(
urlReadablePath(name),
isDirectory: false
)
.path
case .article(let bundleName, let articleName):
// Format: "/documentation/MyBundle/MyArticle"
return Self.documentationFolderURL.appendingPathComponent(urlReadablePath(bundleName)).appendingPathComponent(urlReadablePath(articleName)).path
return Self.documentationFolderURL
.appendingPathComponent(
urlReadablePath(bundleName),
isDirectory: false
)
.appendingPathComponent(
urlReadablePath(articleName),
isDirectory: false
)
.path
case .technology(let technologyName):
// Format: "/tutorials/MyTechnology"
return Self.tutorialsFolderURL.appendingPathComponent(urlReadablePath(technologyName)).path
return Self.tutorialsFolderURL
.appendingPathComponent(
urlReadablePath(technologyName),
isDirectory: false
)
.path
case .tutorial(let bundleName, let tutorialName):
// Format: "/tutorials/MyBundle/MyTutorial"
return Self.tutorialsFolderURL.appendingPathComponent(urlReadablePath(bundleName)).appendingPathComponent(urlReadablePath(tutorialName)).path
return Self.tutorialsFolderURL
.appendingPathComponent(
urlReadablePath(bundleName),
isDirectory: false
)
.appendingPathComponent(
urlReadablePath(tutorialName),
isDirectory: false
)
.path
}
}
}
Expand Down Expand Up @@ -128,9 +165,9 @@ public struct NodeURLGenerator {
public func urlForReference(_ reference: ResolvedTopicReference, fileSafePath safePath: String) -> URL {
if safePath.isEmpty {
// Return the root path for the conversion: /documentation.json
return baseURL.appendingPathComponent("documentation")
return baseURL.appendingPathComponent("documentation", isDirectory: false)
} else {
let url = baseURL.appendingPathComponent(safePath)
let url = baseURL.appendingPathComponent(safePath, isDirectory: false)
return url.withFragment(reference.url.fragment)
}
}
Expand Down
5 changes: 4 additions & 1 deletion Sources/SwiftDocC/Model/Identifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,10 @@ public struct UnresolvedTopicReference: Hashable, CustomStringConvertible {
/// - parent: The resolved parent reference of the unresolved reference.
/// - unresolvedChild: The other unresolved reference.
public init(parent: ResolvedTopicReference, unresolvedChild: UnresolvedTopicReference) {
var components = URLComponents(url: parent.url.appendingPathComponent(unresolvedChild.path), resolvingAgainstBaseURL: false)!
var components = URLComponents(
url: parent.url.appendingPathComponent(unresolvedChild.path, isDirectory: false),
resolvingAgainstBaseURL: false
)!
components.fragment = unresolvedChild.fragment
self.init(topicURL: ValidatedURL(components: components))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ extension URLReference {
/// - Parameter path: The path of the file.
/// - Returns: The destination URL for the given file path.
func destinationURL(for path: String) -> URL {
return Self.baseURL.appendingPathComponent(path)
return Self.baseURL.appendingPathComponent(path, isDirectory: false)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ struct ConvertFileWritingConsumer: ConvertOutputConsumer {
let assetName = sourceURL.lastPathComponent
try fileManager.copyItem(
at: sourceURL,
to: destinationFolder.appendingPathComponent(assetName)
to: destinationFolder.appendingPathComponent(assetName, isDirectory: false)
)
}
}
Expand Down Expand Up @@ -178,7 +178,7 @@ struct ConvertFileWritingConsumer: ConvertOutputConsumer {
// Injects a <template> tag into the index.html <body> using the contents of
// the given URL for the provided HTML file
private func injectCustomTemplate(_ templateURL: URL, identifiedBy id: CustomTemplateIdentifier) throws {
let index = targetFolder.appendingPathComponent("index.html")
let index = targetFolder.appendingPathComponent("index.html", isDirectory: false)
guard let indexData = fileManager.contents(atPath: index.path),
let indexContents = String(data: indexData, encoding: .utf8),
let templateData = fileManager.contents(atPath: templateURL.path),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ extension ConvertAction {
/// - outputURL: The target directory to create the index file.
/// - bundleIdentifier: The identifier of the bundle being indexed.
init(outputURL: URL, bundleIdentifier: String) throws {
let indexURL = outputURL.appendingPathComponent("index")
let indexURL = outputURL.appendingPathComponent("index", isDirectory: true)
indexBuilder = Synchronized<NavigatorIndex.Builder>(
NavigatorIndex.Builder(renderNodeProvider: nil,
outputURL: indexURL,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ public struct CoverageAction: Action {

let summaryString = try CoverageDataEntry.generateSummary(
ofDataAt: workingDirectory.appendingPathComponent(
ConvertFileWritingConsumer.docCoverageFileName),
ConvertFileWritingConsumer.docCoverageFileName,
isDirectory: false
),
fileManager: fileManager,
shouldGenerateBrief: true,
shouldGenerateDetailed: (documentationCoverageOptions.level == .detailed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public protocol DirectoryPathOption: ParsableArguments {
extension DirectoryPathOption {
/// The provided ``url`` or the "current directory" if the user didn't provide an argument.
public var urlOrFallback: URL {
return url ?? URL(fileURLWithPath: ".")
return url ?? URL(fileURLWithPath: ".", isDirectory: true)
}

public mutating func validate() throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public struct OutOfProcessLinkResolverOption: ParsableArguments {
/// the environment variable `DOCC_LINK_RESOLVER_EXECUTABLE`.
var linkResolverExecutableURL: URL? {
ProcessInfo.processInfo.environment[OutOfProcessLinkResolverOption.environmentVariableKey]
.map { URL(fileURLWithPath: $0) }
.map { URL(fileURLWithPath: $0, isDirectory: false) }
}

public mutating func validate() throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ extension Docc {
neededFileName = HTMLTemplate.indexFileName.rawValue
}

let indexTemplate = templateURL.appendingPathComponent(neededFileName)
let indexTemplate = templateURL.appendingPathComponent(neededFileName, isDirectory: false)
if !FileManager.default.fileExists(atPath: indexTemplate.path) {
throw TemplateOption.invalidHTMLTemplateError(
path: templateURL.path,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ extension Docc {

/// The path to the directory that all build output should be placed in.
public var outputURL: URL {
documentationBundle.urlOrFallback.appendingPathComponent("index")
documentationBundle.urlOrFallback.appendingPathComponent("index", isDirectory: true)
}

// MARK: - Execution
Expand Down

0 comments on commit 7ce996e

Please sign in to comment.