Skip to content
Merged
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
2 changes: 1 addition & 1 deletion Sources/CLI/cmd/agent/skills/AgentSkillsGetCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ struct AgentSkillsGetCommand: ParsableCommand, GlobalOptionsProviding {
var name: String

mutating func run() throws {
try run(deps: Dependencies.shared)
try run(deps: AppleDocs.dependencies)
}

func run(deps: Deps) throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ struct AgentSkillsInstallCommand: ParsableCommand, GlobalOptionsProviding {
}

mutating func run() throws {
try run(deps: Dependencies.shared)
try run(deps: AppleDocs.dependencies)
}

func run(deps: Deps) throws {
Expand Down
2 changes: 1 addition & 1 deletion Sources/CLI/cmd/agent/skills/AgentSkillsListCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct AgentSkillsListCommand: ParsableCommand, GlobalOptionsProviding {
)

mutating func run() throws {
run(deps: Dependencies.shared)
run(deps: AppleDocs.dependencies)
}

func run(deps: Deps) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ struct AgentSkillsUninstallCommand: ParsableCommand, GlobalOptionsProviding {
}

mutating func run() throws {
try run(deps: Dependencies.shared)
try run(deps: AppleDocs.dependencies)
}

func run(deps: Deps) throws {
Expand Down
2 changes: 1 addition & 1 deletion Sources/CLI/cmd/cache/CacheCleanCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct CacheCleanCommand: ParsableCommand, GlobalOptionsProviding {
)

mutating func run() throws {
run(deps: Dependencies.shared)
run(deps: AppleDocs.dependencies)
}

func run(deps: Deps) {
Expand Down
2 changes: 1 addition & 1 deletion Sources/CLI/cmd/technologies/TechnologiesListCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ struct TechnologiesListCommand: AsyncParsableCommand, GlobalOptionsProviding {
)

mutating func run() async throws {
try await run(deps: Dependencies.shared)
try await run(deps: AppleDocs.dependencies)
}

func run(deps: Deps) async throws {
Expand Down
2 changes: 1 addition & 1 deletion Sources/CLI/cmd/types/TypesListCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ struct TypesListCommand: AsyncParsableCommand, GlobalOptionsProviding {
var technology: String

mutating func run() async throws {
try await run(deps: Dependencies.shared)
try await run(deps: AppleDocs.dependencies)
}

func run(deps: Deps) async throws {
Expand Down
2 changes: 1 addition & 1 deletion Sources/CLI/cmd/types/TypesSearchCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct TypesSearchCommand: AsyncParsableCommand, GlobalOptionsProviding {
var technology: String

mutating func run() async throws {
try await run(deps: Dependencies.shared)
try await run(deps: AppleDocs.dependencies)
}

func run(deps: Deps) async throws {
Expand Down
2 changes: 1 addition & 1 deletion Sources/CLI/cmd/types/TypesViewCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ struct TypesViewCommand: AsyncParsableCommand, GlobalOptionsProviding {
var technology: String

mutating func run() async throws {
try await run(deps: Dependencies.shared)
try await run(deps: AppleDocs.dependencies)
}

func run(deps: Deps) async throws {
Expand Down
13 changes: 11 additions & 2 deletions Sources/CLI/main/AppleDocs.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import ArgumentParser
import Foundation
import Logging

@main
enum AppleDocs {
private static let logger = Logger(label: "com.techprimate.apple-docs")
private static let telemetry = DefaultTelemetry(
// Telemetry starts before SwiftLog is bootstrapped. Resolve its logger only when logging an event.
logger: { Logger(label: "com.techprimate.apple-docs.telemetry") },
environment: ProcessInfo.processInfo.environment
)
static let dependencies = Dependencies(telemetry: telemetry)

@MainActor
static func main() async {
let telemetry = Dependencies.shared.telemetry
let telemetry = Self.telemetry
telemetry.start()
// Telemetry installs a SIGPIPE handler during start, so configure the terminal afterward.
Dependencies.shared.terminalSetup.configure()
TerminalSetup().configure()
var loggingConfigured = false

do {
Expand All @@ -20,6 +27,8 @@ enum AppleDocs {
telemetry: telemetry
)
loggingConfigured = true
// Construct command dependencies only after their log handlers are installed.
_ = Self.dependencies
Self.logger.debug("CLI command parsed")
if var asyncCommand = command as? any AsyncParsableCommand {
try await asyncCommand.run()
Expand Down
25 changes: 8 additions & 17 deletions Sources/CLI/main/Dependencies.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,15 @@ import Logging
#endif

struct Dependencies: Sendable {
static let shared = Dependencies()

let terminalCapabilities = DefaultTerminalCapabilities()
let commandOutputWriter = DefaultCommandOutputWriter()
let terminalSetup = TerminalSetup()
let telemetry = DefaultTelemetry(
// Telemetry starts before SwiftLog is bootstrapped. Resolve its logger only when logging an event.
logger: { Logger(label: "com.techprimate.apple-docs.telemetry") },
environment: ProcessInfo.processInfo.environment
)
let telemetry: DefaultTelemetry
let httpCache: URLCache?
let httpDataTransport: URLSession
let documentationRepository: DefaultAppleDocumentationRepository<DefaultAppleDocumentationClient<URLSession>>

// Commands resolve the repository after logging is bootstrapped.
var documentationRepository: DefaultAppleDocumentationRepository<DefaultAppleDocumentationClient<URLSession>> {
DefaultAppleDocumentationRepository(
logger: Logger(label: "com.techprimate.apple-docs.repository"),
dependencies: DefaultAppleDocumentationClient(
logger: Logger(label: "com.techprimate.apple-docs.client"), dependencies: httpDataTransport))
}

init() {
init(telemetry: DefaultTelemetry) {
self.telemetry = telemetry
if let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first {
let cacheDirectory = cachesDirectory.appendingPathComponent("com.techprimate.apple-docs", isDirectory: true)
#if canImport(FoundationNetworking)
Expand All @@ -46,6 +33,10 @@ struct Dependencies: Sendable {
configuration.urlCache = httpCache
}
httpDataTransport = URLSession(configuration: configuration)
documentationRepository = DefaultAppleDocumentationRepository(
logger: Logger(label: "com.techprimate.apple-docs.repository"),
dependencies: DefaultAppleDocumentationClient(
logger: Logger(label: "com.techprimate.apple-docs.client"), dependencies: httpDataTransport))
}

var documentationCache: URLCache? {
Expand Down
16 changes: 13 additions & 3 deletions Tests/CLITests/main/DependenciesTests.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Foundation
import Logging
import Testing

@testable import CLI
Expand All @@ -12,8 +13,8 @@ struct DependenciesTests {
@Test("separate dependency instances own separate transports and caches")
func isolatesInstances() throws {
// -- Arrange --
let first = Dependencies()
let second = Dependencies()
let first = makeDependencies()
let second = makeDependencies()

// -- Act --
let firstCache = try #require(first.documentationCache)
Expand All @@ -29,7 +30,7 @@ struct DependenciesTests {
@Test("uses a dedicated large documentation cache")
func usesDedicatedDocumentationCache() throws {
// -- Arrange --
let dependencies = Dependencies.shared
let dependencies = makeDependencies()
let session = dependencies.httpDataTransport

// -- Act --
Expand All @@ -41,4 +42,13 @@ struct DependenciesTests {
#expect(cache === documentationCache)
#expect(cache.diskCapacity == 1_000_000_000)
}

private func makeDependencies() -> Dependencies {
Dependencies(
telemetry: DefaultTelemetry(
logger: { Logger(label: "test") { _ in SwiftLogNoOpLogHandler() } },
environment: ["TELEMETRY_DISABLED": "true"]
)
)
}
}
Loading