Skip to content

Commit 4f86d6b

Browse files
authored
use verbosity flags to drive diagnostics logging level (#3809)
motivation: allow users to specify verbosity which would impact how much diagnostic information is outputed changes: * add "very-verbose" CLI flag * drive diagnostics logging level based on verbosity flags: verbose == .info, very-verbose == .debug * filter diagnostic printing based on log level * pass logLevel where appropriate instead of isVerbose * add test
1 parent 67f5bbd commit 4f86d6b

11 files changed

+211
-85
lines changed

Sources/Basics/Observability.swift

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,11 +292,28 @@ public struct Diagnostic: CustomStringConvertible, Equatable {
292292
Self(severity: .debug, message: message.description, metadata: metadata)
293293
}
294294

295-
public enum Severity: Equatable {
295+
public enum Severity: Comparable {
296296
case error
297297
case warning
298298
case info
299299
case debug
300+
301+
internal var naturalIntegralValue: Int {
302+
switch self {
303+
case .debug:
304+
return 0
305+
case .info:
306+
return 1
307+
case .warning:
308+
return 2
309+
case .error:
310+
return 3
311+
}
312+
}
313+
314+
public static func < (lhs: Self, rhs: Self) -> Bool {
315+
return lhs.naturalIntegralValue < rhs.naturalIntegralValue
316+
}
300317
}
301318
}
302319

Sources/Build/BuildOperation.swift

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
5252
/// The output stream for the build delegate.
5353
private let outputStream: OutputByteStream
5454

55+
/// The verbosity level to print out at
56+
private let logLevel: Basics.Diagnostic.Severity
57+
5558
/// File system to operate on
5659
private let fileSystem: TSCBasic.FileSystem
5760

@@ -68,6 +71,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
6871
packageGraphLoader: @escaping () throws -> PackageGraph,
6972
pluginInvoker: @escaping (PackageGraph) throws -> [ResolvedTarget: [PluginInvocationResult]],
7073
outputStream: OutputByteStream,
74+
logLevel: Basics.Diagnostic.Severity,
7175
fileSystem: TSCBasic.FileSystem,
7276
observabilityScope: ObservabilityScope
7377
) {
@@ -76,6 +80,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
7680
self.packageGraphLoader = packageGraphLoader
7781
self.pluginInvoker = pluginInvoker
7882
self.outputStream = outputStream
83+
self.logLevel = logLevel
7984
self.fileSystem = fileSystem
8085
self.observabilityScope = observabilityScope.makeChildScope(description: "Build Operation")
8186
}
@@ -127,7 +132,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
127132
public func build(subset: BuildSubset) throws {
128133
// Create the build system.
129134
let buildDescription = try self.getBuildDescription()
130-
let buildSystem = try createBuildSystem(with: buildDescription)
135+
let buildSystem = try self.createBuildSystem(buildDescription: buildDescription)
131136
self.buildSystem = buildSystem
132137

133138
// Perform the build.
@@ -224,7 +229,7 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
224229

225230
/// Build the package structure target.
226231
private func buildPackageStructure() throws {
227-
let buildSystem = try self.createBuildSystem(with: nil)
232+
let buildSystem = try self.createBuildSystem(buildDescription: .none)
228233
self.buildSystem = buildSystem
229234

230235
// Build the package structure target which will re-generate the llbuild manifest, if necessary.
@@ -237,12 +242,9 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
237242
///
238243
/// The build description should only be omitted when creating the build system for
239244
/// building the package structure target.
240-
private func createBuildSystem(
241-
with buildDescription: BuildDescription?
242-
) throws -> SPMLLBuild.BuildSystem {
245+
private func createBuildSystem(buildDescription: BuildDescription?) throws -> SPMLLBuild.BuildSystem {
243246
// Figure out which progress bar we have to use during the build.
244-
let isVerbose = verbosity != .concise
245-
let progressAnimation: ProgressAnimationProtocol = isVerbose
247+
let progressAnimation: ProgressAnimationProtocol = self.logLevel.isVerbose
246248
? MultiLineNinjaProgressAnimation(stream: self.outputStream)
247249
: NinjaProgressAnimation(stream: self.outputStream)
248250

@@ -260,11 +262,11 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
260262
buildExecutionContext: buildExecutionContext,
261263
outputStream: self.outputStream,
262264
progressAnimation: progressAnimation,
265+
logLevel: self.logLevel,
263266
observabilityScope: self.observabilityScope,
264267
delegate: self.delegate
265268
)
266269
self.buildSystemDelegate = buildSystemDelegate
267-
buildSystemDelegate.isVerbose = isVerbose
268270

269271
let databasePath = buildParameters.dataPath.appending(component: "build.db").pathString
270272
let buildSystem = SPMLLBuild.BuildSystem(
@@ -273,7 +275,9 @@ public final class BuildOperation: PackageStructureDelegate, SPMBuildCore.BuildS
273275
delegate: buildSystemDelegate,
274276
schedulerLanes: buildParameters.jobs
275277
)
276-
buildSystemDelegate.onCommmandFailure = {
278+
279+
// TODO: this seems fragile, perhaps we replace commandFailureHandler by adding relevant calls in the delegates chain
280+
buildSystemDelegate.commandFailureHandler = {
277281
buildSystem.cancel()
278282
self.delegate?.buildSystemDidCancel(self)
279283
}
@@ -418,3 +422,9 @@ extension BuildSubset {
418422
}
419423
}
420424
}
425+
426+
extension Basics.Diagnostic.Severity {
427+
var isVerbose: Bool {
428+
return self <= .info
429+
}
430+
}

Sources/Build/BuildOperationBuildSystemDelegateHandler.swift

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -368,11 +368,11 @@ final class CopyCommand: CustomLLBuildCommand {
368368

369369
/// Convenient llbuild build system delegate implementation
370370
final class BuildOperationBuildSystemDelegateHandler: LLBuildBuildSystemDelegate, SwiftCompilerOutputParserDelegate {
371-
var outputStream: ThreadSafeOutputByteStream
372-
var progressAnimation: ProgressAnimationProtocol
373-
var onCommmandFailure: (() -> Void)?
374-
var isVerbose: Bool = false
375-
weak var delegate: SPMBuildCore.BuildSystemDelegate?
371+
private let outputStream: ThreadSafeOutputByteStream
372+
private let progressAnimation: ProgressAnimationProtocol
373+
var commandFailureHandler: (() -> Void)?
374+
private let logLevel: Basics.Diagnostic.Severity
375+
private weak var delegate: SPMBuildCore.BuildSystemDelegate?
376376
private let buildSystem: SPMBuildCore.BuildSystem
377377
private let queue = DispatchQueue(label: "org.swift.swiftpm.build-delegate")
378378
private var taskTracker = CommandTaskTracker()
@@ -390,17 +390,19 @@ final class BuildOperationBuildSystemDelegateHandler: LLBuildBuildSystemDelegate
390390
buildExecutionContext: BuildExecutionContext,
391391
outputStream: OutputByteStream,
392392
progressAnimation: ProgressAnimationProtocol,
393+
logLevel: Basics.Diagnostic.Severity,
393394
observabilityScope: ObservabilityScope,
394395
delegate: SPMBuildCore.BuildSystemDelegate?
395396
) {
397+
self.buildSystem = buildSystem
398+
self.buildExecutionContext = buildExecutionContext
396399
// FIXME: Implement a class convenience initializer that does this once they are supported
397400
// https://forums.swift.org/t/allow-self-x-in-class-convenience-initializers/15924
398401
self.outputStream = outputStream as? ThreadSafeOutputByteStream ?? ThreadSafeOutputByteStream(outputStream)
399402
self.progressAnimation = progressAnimation
400-
self.buildExecutionContext = buildExecutionContext
401-
self.delegate = delegate
402-
self.buildSystem = buildSystem
403+
self.logLevel = logLevel
403404
self.observabilityScope = observabilityScope
405+
self.delegate = delegate
404406

405407
let swiftParsers = buildExecutionContext.buildDescription?.swiftCommands.mapValues { tool in
406408
SwiftCompilerOutputParser(targetName: tool.moduleName, delegate: self)
@@ -434,7 +436,7 @@ final class BuildOperationBuildSystemDelegateHandler: LLBuildBuildSystemDelegate
434436
}
435437

436438
func hadCommandFailure() {
437-
onCommmandFailure?()
439+
self.commandFailureHandler?()
438440
}
439441

440442
func handleDiagnostic(_ diagnostic: SPMLLBuild.Diagnostic) {
@@ -451,7 +453,7 @@ final class BuildOperationBuildSystemDelegateHandler: LLBuildBuildSystemDelegate
451453
}
452454

453455
func commandStatusChanged(_ command: SPMLLBuild.Command, kind: CommandStatusKind) {
454-
guard !isVerbose else { return }
456+
guard !self.logLevel.isVerbose else { return }
455457
guard command.shouldShowStatus else { return }
456458
guard !swiftParsers.keys.contains(command.name) else { return }
457459

@@ -472,7 +474,7 @@ final class BuildOperationBuildSystemDelegateHandler: LLBuildBuildSystemDelegate
472474

473475
queue.async {
474476
self.delegate?.buildSystem(self.buildSystem, didStartCommand: BuildSystemCommand(command))
475-
if self.isVerbose {
477+
if self.logLevel.isVerbose {
476478
self.outputStream <<< command.verboseDescription <<< "\n"
477479
self.outputStream.flush()
478480
}
@@ -490,7 +492,7 @@ final class BuildOperationBuildSystemDelegateHandler: LLBuildBuildSystemDelegate
490492
queue.async {
491493
self.delegate?.buildSystem(self.buildSystem, didFinishCommand: BuildSystemCommand(command))
492494

493-
if !self.isVerbose {
495+
if !self.logLevel.isVerbose {
494496
let targetName = self.swiftParsers[command.name]?.targetName
495497
self.taskTracker.commandFinished(command, result: result, targetName: targetName)
496498
self.updateProgress()
@@ -580,7 +582,7 @@ final class BuildOperationBuildSystemDelegateHandler: LLBuildBuildSystemDelegate
580582

581583
func swiftCompilerOutputParser(_ parser: SwiftCompilerOutputParser, didParse message: SwiftCompilerMessage) {
582584
queue.async {
583-
if self.isVerbose {
585+
if self.logLevel.isVerbose {
584586
if let text = message.verboseProgressText {
585587
self.outputStream <<< text <<< "\n"
586588
self.outputStream.flush()
@@ -592,7 +594,7 @@ final class BuildOperationBuildSystemDelegateHandler: LLBuildBuildSystemDelegate
592594

593595
if let output = message.standardOutput {
594596
// first we want to print the output so users have it handy
595-
if !self.isVerbose {
597+
if !self.logLevel.isVerbose {
596598
self.progressAnimation.clear()
597599
}
598600

@@ -614,7 +616,7 @@ final class BuildOperationBuildSystemDelegateHandler: LLBuildBuildSystemDelegate
614616
func swiftCompilerOutputParser(_ parser: SwiftCompilerOutputParser, didFailWith error: Error) {
615617
let message = (error as? LocalizedError)?.errorDescription ?? error.localizedDescription
616618
self.observabilityScope.emit(.swiftCompilerOutputParsingError(message))
617-
onCommmandFailure?()
619+
self.commandFailureHandler?()
618620
}
619621

620622
func buildComplete(success: Bool) {

Sources/Commands/APIDigester.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ struct APIDigesterBaselineDumper {
5858
for modulesToDiff: Set<String>,
5959
at baselineDir: AbsolutePath?,
6060
force: Bool,
61-
outputStream: OutputByteStream
61+
outputStream: OutputByteStream,
62+
logLevel: Diagnostic.Severity
6263
) throws -> AbsolutePath {
6364
var modulesToDiff = modulesToDiff
6465
let apiDiffDir = inputBuildParameters.apiDiff
@@ -126,6 +127,7 @@ struct APIDigesterBaselineDumper {
126127
packageGraphLoader: { graph },
127128
pluginInvoker: { _ in [:] },
128129
outputStream: outputStream,
130+
logLevel: logLevel,
129131
fileSystem: localFileSystem,
130132
observabilityScope: observabilityScope
131133
)

Sources/Commands/Options.swift

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,22 @@ struct BuildFlagsGroup: ParsableArguments {
2020
parsing: .unconditionalSingleValue,
2121
help: "Pass flag through to all C compiler invocations")
2222
var cCompilerFlags: [String] = []
23-
23+
2424
@Option(name: .customLong("Xswiftc", withSingleDash: true),
2525
parsing: .unconditionalSingleValue,
2626
help: "Pass flag through to all Swift compiler invocations")
2727
var swiftCompilerFlags: [String] = []
28-
28+
2929
@Option(name: .customLong("Xlinker", withSingleDash: true),
3030
parsing: .unconditionalSingleValue,
3131
help: "Pass flag through to all linker invocations")
3232
var linkerFlags: [String] = []
33-
33+
3434
@Option(name: .customLong("Xcxx", withSingleDash: true),
3535
parsing: .unconditionalSingleValue,
3636
help: "Pass flag through to all C++ compiler invocations")
3737
var cxxCompilerFlags: [String] = []
38-
38+
3939
@Option(name: .customLong("Xxcbuild", withSingleDash: true),
4040
parsing: .unconditionalSingleValue,
4141
help: ArgumentHelp(
@@ -56,7 +56,7 @@ struct BuildFlagsGroup: ParsableArguments {
5656
xswiftc: swiftCompilerFlags,
5757
xlinker: linkerFlags)
5858
}
59-
59+
6060
init() {}
6161
}
6262

@@ -77,7 +77,7 @@ extension AbsolutePath: ExpressibleByArgument {
7777
self = path
7878
}
7979
}
80-
80+
8181
public static var defaultCompletionKind: CompletionKind {
8282
// This type is most commonly used to select a directory, not a file.
8383
// Specify '.file()' in an argument declaration when necessary.
@@ -114,7 +114,7 @@ public extension Sanitizer {
114114
public struct SwiftToolOptions: ParsableArguments {
115115
@OptionGroup()
116116
var buildFlagsGroup: BuildFlagsGroup
117-
117+
118118
/// Custom arguments to pass to C compiler, swift compiler and the linker.
119119
var buildFlags: BuildFlags {
120120
buildFlagsGroup.buildFlags
@@ -162,12 +162,13 @@ public struct SwiftToolOptions: ParsableArguments {
162162
@Flag(name: .customLong("prefetching"), inversion: .prefixedEnableDisable)
163163
var shouldEnableResolverPrefetching: Bool = true
164164

165-
// FIXME: We need to allow -vv type options for this.
166165
/// The verbosity of informational output.
167-
@Flag(name: .shortAndLong, help: "Increase verbosity of informational output")
166+
@Flag(name: .shortAndLong, help: "Increase verbosity to include informational output")
168167
var verbose: Bool = false
169-
170-
var verbosity: Int { verbose ? 1 : 0 }
168+
169+
/// The verbosity of informational output.
170+
@Flag(name: [.long, .customLong("vv")], help: "Increase verbosity to include debug output")
171+
var veryVerbose: Bool = false
171172

172173
/// Disables sandboxing when executing subprocesses.
173174
@Flag(name: .customLong("disable-sandbox"), help: "Disable using the sandbox when executing subprocesses")
@@ -198,11 +199,11 @@ public struct SwiftToolOptions: ParsableArguments {
198199
/// The compilation destination’s target triple.
199200
@Option(name: .customLong("triple"), transform: Triple.init)
200201
var customCompileTriple: Triple?
201-
202+
202203
/// Path to the compilation destination’s SDK.
203204
@Option(name: .customLong("sdk"))
204205
var customCompileSDK: AbsolutePath?
205-
206+
206207
/// Path to the compilation destination’s toolchain.
207208
@Option(name: .customLong("toolchain"))
208209
var customCompileToolchain: AbsolutePath?
@@ -232,13 +233,13 @@ public struct SwiftToolOptions: ParsableArguments {
232233
var enabledSanitizers: EnabledSanitizers {
233234
EnabledSanitizers(Set(sanitizers))
234235
}
235-
236+
236237
/// Whether to enable code coverage.
237238
@Flag(name: .customLong("code-coverage"),
238239
inversion: .prefixedEnableDisable,
239240
help: "Enable code coverage")
240241
var shouldEnableCodeCoverage: Bool = false
241-
242+
242243
/// Use Package.resolved file for resolving dependencies.
243244
@Flag(name: [.long, .customLong("disable-automatic-resolution"), .customLong("only-use-versions-from-resolved-file")], help: "Only use versions from the Package.resolved file and fail resolution if it is out-of-date")
244245
var forceResolvedVersions: Bool = false
@@ -250,7 +251,7 @@ public struct SwiftToolOptions: ParsableArguments {
250251
case autoIndexStore
251252
case enableIndexStore
252253
case disableIndexStore
253-
254+
254255
/// The mode to use for indexing-while-building feature.
255256
var indexStoreMode: BuildParameters.IndexStoreMode {
256257
switch self {
@@ -263,7 +264,7 @@ public struct SwiftToolOptions: ParsableArguments {
263264
}
264265
}
265266
}
266-
267+
267268
@Flag(help: "Enable or disable indexing-while-building feature")
268269
var indexStoreMode: StoreMode = .autoIndexStore
269270

@@ -326,14 +327,14 @@ public struct SwiftToolOptions: ParsableArguments {
326327
exclusivity: .exclusive,
327328
help: "Load credentials from a .netrc file")
328329
var netrc: Bool = true
329-
330+
330331
/// The path to the .netrc file used when `netrc` is `true`.
331332
@Option(
332333
name: .customLong("netrc-file"),
333334
help: "Specify the .netrc file path.",
334335
completion: .file())
335336
var netrcFilePath: AbsolutePath?
336-
337+
337338
/// Whether to use keychain for authenticating with remote servers
338339
/// when downloading binary artifacts or communicating with a registry.
339340
#if canImport(Security)
@@ -353,6 +354,6 @@ public struct SwiftToolOptions: ParsableArguments {
353354

354355
@Flag(name: .customLong("netrc-optional"), help: .hidden)
355356
var _deprecated_netrcOptional: Bool = false
356-
357+
357358
public init() {}
358359
}

Sources/Commands/SwiftPackageTool.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,8 @@ extension SwiftPackageTool {
408408
for: modulesToDiff,
409409
at: overrideBaselineDir,
410410
force: regenerateBaseline,
411-
outputStream: swiftTool.outputStream
411+
outputStream: swiftTool.outputStream,
412+
logLevel: swiftTool.logLevel
412413
)
413414

414415
let results = ThreadSafeArrayStore<SwiftAPIDigester.ComparisonResult>()

0 commit comments

Comments
 (0)