Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Use throwing readToEnd for debugging and error handling
  • Loading branch information
MaxDesiatov committed Aug 2, 2023
commit f042a6849fc64a097046f06eb6015c72ac00785d
3 changes: 2 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ let swiftSettings: [SwiftSetting] = [
let package = Package(
name: "SwiftDocC",
platforms: [
.macOS(.v10_15),
.macOS(.v11),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bumped to .v11 per a discussion with @franklinsch, this allows us to use throwing FileHandle.readToEnd() unlike the unsafe non-throwing FileHandle.readDataToEndOfFile that crashes the test suite on Linux.

.iOS(.v13)
],
products: [
Expand Down Expand Up @@ -91,6 +91,7 @@ let package = Package(
.target(
name: "SwiftDocCTestUtilities",
dependencies: [
"SwiftDocC",
.product(name: "SymbolKit", package: "swift-docc-symbolkit"),
],
swiftSettings: swiftSettings
Expand Down
5 changes: 3 additions & 2 deletions Sources/SwiftDocC/Indexing/Navigator/NavigatorIndex+Ext.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@ public class FileSystemRenderNodeProvider: RenderNodeProvider {
if file.url.pathExtension.lowercased() == "json" {
do {
let fileHandle = try FileHandle(forReadingFrom: file.url)
let data = fileHandle.readDataToEndOfFile()
renderNode = try RenderNode.decode(fromJSON: data)
if let data = try fileHandle.readToEnd() {
renderNode = try RenderNode.decode(fromJSON: data)
}
} catch {
let diagnostic = Diagnostic(source: file.url,
severity: .warning,
Expand Down
20 changes: 10 additions & 10 deletions Sources/SwiftDocC/Indexing/Navigator/NavigatorIndex.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,8 @@ public class NavigatorIndex {

/// A specific error to describe issues when processing a `NavigatorIndex`.
public enum Error: Swift.Error, DescribedError {

/// Missing bundle identifier.
case missingBundleIndentifier
case missingBundleIdentifier

/// A RenderNode has no title and won't be indexed.
case missingTitle(description: String)
Expand All @@ -72,8 +71,8 @@ public class NavigatorIndex {
case navigatorIndexIsNil

public var errorDescription: String {
switch self {
case .missingBundleIndentifier:
switch self {
case .missingBundleIdentifier:
return "A navigator index requires a bundle identifier, which is missing."
case .missingTitle:
return "The page has no valid title available."
Expand Down Expand Up @@ -169,16 +168,17 @@ public class NavigatorIndex {

let information = try environment.openDatabase(named: "information", flags: [])

let availabilityIndexFileHandle = try FileHandle(
forReadingFrom: url.appendingPathComponent("availability.index", isDirectory: false)
)
let data = availabilityIndexFileHandle.readDataToEndOfFile()
let availabilityIndexFileURL = url.appendingPathComponent("availability.index", isDirectory: false)
let availabilityIndexFileHandle = try FileHandle(forReadingFrom: availabilityIndexFileURL)
guard let data = try availabilityIndexFileHandle.readToEnd() else {
throw FileSystemError.noDataReadFromFile(path: availabilityIndexFileURL.path)
}
let plistDecoder = PropertyListDecoder()
let availabilityIndex = try plistDecoder.decode(AvailabilityIndex.self, from: data)
let bundleIdentifier = bundleIdentifier ?? information.get(type: String.self, forKey: NavigatorIndex.bundleKey) ?? NavigatorIndex.UnknownBundleIdentifier

guard bundleIdentifier != NavigatorIndex.UnknownBundleIdentifier else {
throw Error.missingBundleIndentifier
throw Error.missingBundleIdentifier
}

// Use `.fnv1` by default if no path hasher is set for compatibility reasons.
Expand Down Expand Up @@ -285,7 +285,7 @@ public class NavigatorIndex {
self.availabilityIndex = AvailabilityIndex()

guard self.bundleIdentifier != NavigatorIndex.UnknownBundleIdentifier else {
throw Error.missingBundleIndentifier
throw Error.missingBundleIdentifier
}
}

Expand Down
10 changes: 7 additions & 3 deletions Sources/SwiftDocC/Indexing/Navigator/NavigatorTree.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,9 @@ public class NavigatorTree {
broadcast: BroadcastCallback?
) throws {
let fileHandle = try FileHandle(forReadingFrom: url)
let data = fileHandle.readDataToEndOfFile()
guard let data = try fileHandle.readToEnd() else {
throw Error.cannotOpenFile(path: url.path)
}
let readingCursor = ReadingCursor(data: data)
self.readingCursor = readingCursor

Expand Down Expand Up @@ -322,10 +324,12 @@ public class NavigatorTree {
presentationIdentifier: String? = nil,
onNodeRead: ((NavigatorTree.Node) -> Void)? = nil
) throws -> NavigatorTree {
guard let fileHandle = FileHandle(forReadingAtPath: path) else {
guard
let fileHandle = FileHandle(forReadingAtPath: path),
let data = try fileHandle.readToEnd()
else {
throw Error.cannotOpenFile(path: path)
}
let data = fileHandle.readDataToEndOfFile()

var map = [UInt32: Node]()
var index: UInt32 = 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,14 @@ enum SVGIDExtractor {
/// Returns nil if any errors are encountered or if an `id` attribute is
/// not found in the given SVG.
static func extractID(from svg: URL) -> String? {
guard let fileHandle = try? FileHandle(forReadingFrom: svg) else {
guard
let fileHandle = try? FileHandle(forReadingFrom: svg),
let data = try? fileHandle.readToEnd()
else {
return nil
}

return _extractID(from: fileHandle.readDataToEndOfFile())
return _extractID(from: data)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ public struct LocalFileSystemDataProvider: DocumentationWorkspaceDataProvider, F
public func contentsOfURL(_ url: URL) throws -> Data {
precondition(url.isFileURL, "Unexpected non-file url '\(url)'.")
let fileHandle = try FileHandle(forReadingFrom: url)
return fileHandle.readDataToEndOfFile()
guard let data = try fileHandle.readToEnd() else {
throw FileSystemError.noDataReadFromFile(path: url.path)
}

return data
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ public struct PrebuiltLocalFileSystemDataProvider: DocumentationWorkspaceDataPro
public func contentsOfURL(_ url: URL) throws -> Data {
precondition(url.isFileURL, "Unexpected non-file url '\(url)'.")
let fileHandle = try FileHandle(forReadingFrom: url)
return fileHandle.readDataToEndOfFile()
guard let data = try fileHandle.readToEnd() else {
throw FileSystemError.noDataReadFromFile(path: url.path)
}

return data
}
}

9 changes: 6 additions & 3 deletions Sources/SwiftDocC/Servers/FileServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public class FileSystemServerProvider: FileServerProvider {
public func data(for path: String) -> Data? {
let finalURL = directoryURL.appendingPathComponent(path)
let fileHandle = try? FileHandle(forReadingFrom: finalURL)
return fileHandle?.readDataToEndOfFile()
return try? fileHandle?.readToEnd()
}

}
Expand Down Expand Up @@ -229,9 +229,12 @@ public class MemoryFileServerProvider: FileServerProvider {

for file in enumerator {
guard let file = file as? String else { fatalError("Enumerator returned an unexpected type.") }
guard let fileHandle = try? FileHandle(forReadingFrom: URL(fileURLWithPath: path).appendingPathComponent(file))
let fileURL = URL(fileURLWithPath: path).appendingPathComponent(file)
guard
let fileHandle = try? FileHandle(forReadingFrom: fileURL),
let data = try? fileHandle.readToEnd()
else { continue }
let data = fileHandle.readDataToEndOfFile()

if recursive == false && file.contains("/") { continue } // skip if subfolder and recursive is disabled
addFile(path: "/\(trimmedSubPath)/\(file)", data: data)
}
Expand Down
21 changes: 21 additions & 0 deletions Sources/SwiftDocC/Utility/Errors/FileSystemError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
This source file is part of the Swift.org open source project

Copyright (c) 2021 Apple Inc. and the Swift project authors
Licensed under Apache License v2.0 with Runtime Library Exception

See https://swift.org/LICENSE.txt for license information
See https://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

public enum FileSystemError: Error, DescribedError {
/// No data could be read from file at `path`.
case noDataReadFromFile(path: String)

public var errorDescription: String {
switch self {
case .noDataReadFromFile(let path):
return "No data could be read from file at `\(path)`"
}
}
}
6 changes: 5 additions & 1 deletion Sources/SwiftDocCTestUtilities/FilesAndFolders.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/

import Foundation
import SwiftDocC
import XCTest

/*
Expand Down Expand Up @@ -201,7 +202,10 @@ public struct CopyOfFile: File, DataRepresentable {
var isDirectory: ObjCBool = false
guard FileManager.default.fileExists(atPath: original.path, isDirectory: &isDirectory), !isDirectory.boolValue else { throw Error.notAFile(original) }
let fileHandle = try FileHandle(forReadingFrom: original)
return fileHandle.readDataToEndOfFile()
guard let data = try fileHandle.readToEnd() else {
throw FileSystemError.noDataReadFromFile(path: original.path)
}
return data
}

public func write(to url: URL) throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import Foundation
import NIO
import NIOHTTP1
import SwiftDocC

/// A request handler that serves the default app page to clients.
///
Expand All @@ -28,9 +29,12 @@ struct DefaultRequestHandler: RequestHandlerFactory {
where ChannelHandler.OutboundOut == HTTPServerResponsePart {

return { context, head in
let fileHandle = try FileHandle(forReadingFrom: self.rootURL.appendingPathComponent("index.html"))
let response = fileHandle.readDataToEndOfFile()

let fileURL = self.rootURL.appendingPathComponent("index.html")
let fileHandle = try FileHandle(forReadingFrom: fileURL)
guard let response = try fileHandle.readToEnd() else {
throw FileSystemError.noDataReadFromFile(path: fileURL.path)
}

var content = context.channel.allocator.buffer(capacity: response.count)
content.writeBytes(response)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,16 @@ struct FileRequestHandler: RequestHandlerFactory {
// Read the file contents
do {
let fileHandle = try FileHandle(forReadingFrom: fileURL)
data = fileHandle.readDataToEndOfFile()
guard let readData = try fileHandle.readToEnd() else {
throw FileSystemError.noDataReadFromFile(path: fileURL.path)
}
data = readData
totalLength = data.count
} catch {
throw RequestError(status: .notFound)
}

// Add Range header if neccessary
// Add Range header if necessary
var headers = HTTPHeaders()
let range = head.headers["Range"].first.flatMap(RangeHeader.init)
if let range = range {
Expand Down
8 changes: 7 additions & 1 deletion Sources/generate-symbol-graph/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ let supportedDirectives: [Directive] = [
)
}

enum SymbolGraphError: Error {
case noDataReadFromFile(path: String)
}

func generateSwiftDocCFrameworkSymbolGraph() throws -> SymbolGraph {
let packagePath = URL(fileURLWithPath: #file)
.deletingLastPathComponent() // generate-symbol-graph
Expand Down Expand Up @@ -207,7 +211,9 @@ func generateSwiftDocCFrameworkSymbolGraph() throws -> SymbolGraph {
)

let symbolGraphFileHandle = try FileHandle(forReadingFrom: symbolGraphURL)
let symbolGraphData = symbolGraphFileHandle.readDataToEndOfFile()
guard let symbolGraphData = try symbolGraphFileHandle.readToEnd() else {
throw SymbolGraphError.noDataReadFromFile(path: symbolGraphURL.path)
}
return try JSONDecoder().decode(SymbolGraph.self, from: symbolGraphData)
}

Expand Down