Skip to content

Commit c807246

Browse files
authored
Simplify argument parsing and processing in the plugin (#88)
* Add a simple utility for working with command line arguments * Use the new argument utility to parse arguments for each tool * Remove unused code * Document all plugin flags in one place * Remove more unused code * Remove misleading code comment * Move definitions of documented option/flag names into DocumentedFlag * Remove incorrect default value (it differs by target kind)
1 parent 6c596f1 commit c807246

32 files changed

+781
-1221
lines changed

Plugins/SharedPackagePluginExtensions/PackageManager+getSymbolGraphsForDocC.swift

Lines changed: 15 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This source file is part of the Swift.org open source project
22
//
3-
// Copyright (c) 2022 Apple Inc. and the Swift project authors
3+
// Copyright (c) 2022-2024 Apple Inc. and the Swift project authors
44
// Licensed under Apache License v2.0 with Runtime Library Exception
55
//
66
// See https://swift.org/LICENSE.txt for license information
@@ -32,44 +32,34 @@ extension PackageManager {
3232
}
3333
}
3434

35-
/// Returns the relevant symbols graphs for Swift-DocC documentation generation for
36-
/// the given target.
35+
/// Returns the relevant symbols graphs for Swift-DocC documentation generation for the given target.
3736
func doccSymbolGraphs(
3837
for target: SwiftSourceModuleTarget,
3938
context: PluginContext,
4039
verbose: Bool,
4140
snippetExtractor: SnippetExtractor?,
42-
customSymbolGraphOptions: [PluginFlag],
43-
minimumAccessLevel: SymbolGraphOptions.AccessLevel? = nil
41+
customSymbolGraphOptions: ParsedSymbolGraphArguments
4442
) throws -> DocCSymbolGraphResult {
4543
// First generate the primary symbol graphs containing information about the
4644
// symbols defined in the target itself.
47-
4845
var symbolGraphOptions = target.defaultSymbolGraphOptions(in: context.package)
49-
if let minimumAccessLevel {
46+
47+
if let rawMinimumAccessLevel = customSymbolGraphOptions.minimumAccessLevel,
48+
let minimumAccessLevel = SymbolGraphOptions.AccessLevel(rawValue: rawMinimumAccessLevel)
49+
{
5050
symbolGraphOptions.minimumAccessLevel = minimumAccessLevel
5151
}
5252

53-
// Modify the symbol graph options with the custom ones
54-
for customSymbolGraphOption in customSymbolGraphOptions {
55-
switch customSymbolGraphOption {
56-
case .extendedTypes.positive:
57-
#if swift(>=5.8)
58-
symbolGraphOptions.emitExtensionBlocks = true
59-
#else
60-
print("warning: detected '--include-extended-types' option, which is incompatible with your swift version (required: 5.8)")
61-
#endif
62-
case .extendedTypes.negative:
63-
#if swift(>=5.8)
64-
symbolGraphOptions.emitExtensionBlocks = false
53+
if customSymbolGraphOptions.skipSynthesizedSymbols == true {
54+
symbolGraphOptions.includeSynthesized = false
55+
}
56+
57+
if let includeExtendedTypes = customSymbolGraphOptions.includeExtendedTypes {
58+
#if swift(<5.8)
59+
print("warning: detected '--\(includeExtendedTypes ? "include" : "exclude")-extended-types' option, which is incompatible with your swift version (required: 5.8)")
6560
#else
66-
print("warning: detected '--exclude-extended-types' option, which is incompatible with your swift version (required: 5.8)")
61+
symbolGraphOptions.emitExtensionBlocks = includeExtendedTypes
6762
#endif
68-
case .skipSynthesizedSymbols:
69-
symbolGraphOptions.includeSynthesized = false
70-
default:
71-
fatalError("error: unknown PluginFlag (\(customSymbolGraphOption.parsedValues.joined(separator: ", "))) detected in symbol graph generation - please create an issue at https://github.com/swiftlang/swift-docc-plugin")
72-
}
7363
}
7464

7565
if verbose {

Plugins/Swift-DocC Convert/SwiftDocCConvert.swift

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -29,36 +29,31 @@ import PackagePlugin
2929
throw ArgumentParsingError.packageDoesNotContainSwiftSourceModuleTargets
3030
}
3131

32-
let verbose = argumentExtractor.extractFlag(named: "verbose") > 0
33-
let isCombinedDocumentationEnabled = argumentExtractor.extractFlag(named: PluginFlag.enableCombinedDocumentationSupportFlagName) > 0
32+
// Parse the given command-line arguments
33+
let parsedArguments = ParsedArguments(argumentExtractor.remainingArguments)
34+
35+
// If the `--help` or `-h` flag was passed, print the plugin's help information and exit.
36+
guard !parsedArguments.pluginArguments.help else {
37+
let helpInfo = try HelpInformation.forAction(.convert, doccExecutableURL: doccExecutableURL)
38+
print(helpInfo)
39+
return
40+
}
41+
42+
let verbose = parsedArguments.pluginArguments.verbose
43+
let isCombinedDocumentationEnabled = parsedArguments.pluginArguments.enableCombinedDocumentation
3444

3545
if isCombinedDocumentationEnabled {
3646
let doccFeatures = try? DocCFeatures(doccExecutable: doccExecutableURL)
3747
guard doccFeatures?.contains(.linkDependencies) == true else {
3848
// The developer uses the combined documentation plugin flag with a DocC version that doesn't support combined documentation.
3949
Diagnostics.error("""
40-
Unsupported use of '--\(PluginFlag.enableCombinedDocumentationSupportFlagName)'. \
50+
Unsupported use of '\(DocumentedFlag.enableCombinedDocumentation.names.preferred)'. \
4151
DocC version at '\(doccExecutableURL.path)' doesn't support combined documentation.
4252
""")
4353
return
4454
}
4555
}
4656

47-
// Parse the given command-line arguments
48-
let parsedArguments = ParsedArguments(argumentExtractor.remainingArguments)
49-
50-
// If the `--help` or `-h` flag was passed, print the plugin's help information
51-
// and exit.
52-
guard !parsedArguments.help else {
53-
let helpInformation = try HelpInformation.forAction(
54-
.convert,
55-
doccExecutableURL: doccExecutableURL
56-
)
57-
58-
print(helpInformation)
59-
return
60-
}
61-
6257
#if swift(>=5.7)
6358
let snippetExtractTool = try context.tool(named: "snippet-extract")
6459
let snippetExtractor = SnippetExtractor(
@@ -79,8 +74,7 @@ import PackagePlugin
7974
context: context,
8075
verbose: verbose,
8176
snippetExtractor: snippetExtractor,
82-
customSymbolGraphOptions: parsedArguments.symbolGraphArguments,
83-
minimumAccessLevel: parsedArguments.arguments.symbolGraphMinimumAccessLevel.flatMap { .init(rawValue: $0) }
77+
customSymbolGraphOptions: parsedArguments.symbolGraphArguments
8478
)
8579

8680
if target.doccCatalogPath == nil,
@@ -120,16 +114,9 @@ import PackagePlugin
120114
doccCatalogPath: target.doccCatalogPath,
121115
targetName: target.name,
122116
symbolGraphDirectoryPath: symbolGraphs.unifiedSymbolGraphsDirectory.path,
123-
outputPath: doccArchiveOutputPath
117+
outputPath: doccArchiveOutputPath,
118+
dependencyArchivePaths: task.dependencies.map { $0.target.doccArchiveOutputPath(in: context) }
124119
)
125-
if isCombinedDocumentationEnabled {
126-
doccArguments.append(CommandLineOption.enableExternalLinkSupport.defaultName)
127-
128-
for taskDependency in task.dependencies {
129-
let dependencyArchivePath = taskDependency.target.doccArchiveOutputPath(in: context)
130-
doccArguments.append(contentsOf: [CommandLineOption.externalLinkDependency.defaultName, dependencyArchivePath])
131-
}
132-
}
133120

134121
if verbose {
135122
let arguments = doccArguments.joined(separator: " ")
@@ -149,7 +136,8 @@ import PackagePlugin
149136
if process.terminationReason == .exit && process.terminationStatus == 0 {
150137
print("Conversion complete! (\(conversionDuration.descriptionInSeconds))")
151138

152-
let describedOutputPath = doccArguments.outputPath ?? "unknown location"
139+
var arguments = CommandLineArguments(doccArguments)
140+
let describedOutputPath = arguments.extractOption(named: DocCArguments.outputPath).last ?? "unknown location"
153141
print("Generated DocC archive at '\(describedOutputPath)'")
154142
} else {
155143
Diagnostics.error("'docc convert' invocation failed with a nonzero exit code: '\(process.terminationStatus)'")

Plugins/Swift-DocC Preview/SwiftDocCPreview.swift

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// This source file is part of the Swift.org open source project
22
//
3-
// Copyright (c) 2022 Apple Inc. and the Swift project authors
3+
// Copyright (c) 2022-2024 Apple Inc. and the Swift project authors
44
// Licensed under Apache License v2.0 with Runtime Library Exception
55
//
66
// See https://swift.org/LICENSE.txt for license information
@@ -28,19 +28,18 @@ import PackagePlugin
2828
possibleTargets = specifiedTargets
2929
}
3030

31-
let verbose = argumentExtractor.extractFlag(named: "verbose") > 0
32-
3331
// Parse the given command-line arguments
3432
let parsedArguments = ParsedArguments(argumentExtractor.remainingArguments)
3533

36-
// If the `--help` or `-h` flag was passed, print the plugin's help information
37-
// and exit.
38-
guard !parsedArguments.help else {
34+
// If the `--help` or `-h` flag was passed, print the plugin's help information and exit.
35+
guard !parsedArguments.pluginArguments.help else {
3936
let helpInfo = try HelpInformation.forAction(.preview, doccExecutableURL: doccExecutableURL)
4037
print(helpInfo)
4138
return
4239
}
4340

41+
let verbose = parsedArguments.pluginArguments.verbose
42+
4443
// Confirm that at least one compatible target was provided.
4544
guard let target = possibleTargets.first else {
4645
Diagnostics.error("""
@@ -84,8 +83,7 @@ import PackagePlugin
8483
context: context,
8584
verbose: verbose,
8685
snippetExtractor: snippetExtractor,
87-
customSymbolGraphOptions: parsedArguments.symbolGraphArguments,
88-
minimumAccessLevel: parsedArguments.arguments.symbolGraphMinimumAccessLevel.flatMap { .init(rawValue: $0) }
86+
customSymbolGraphOptions: parsedArguments.symbolGraphArguments
8987
)
9088

9189
if try FileManager.default.contentsOfDirectory(atPath: symbolGraphs.targetSymbolGraphsDirectory.path).isEmpty {

Sources/SwiftDocCPluginUtilities/Arguments+outputPath.swift

Lines changed: 0 additions & 30 deletions
This file was deleted.

Sources/SwiftDocCPluginUtilities/Arguments+symbolGraphMinimumAccessLevel.swift

Lines changed: 0 additions & 27 deletions
This file was deleted.

Sources/SwiftDocCPluginUtilities/Arguments.swift

Lines changed: 0 additions & 10 deletions
This file was deleted.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// This source file is part of the Swift.org open source project
2+
//
3+
// Copyright (c) 2024 Apple Inc. and the Swift project authors
4+
// Licensed under Apache License v2.0 with Runtime Library Exception
5+
//
6+
// See https://swift.org/LICENSE.txt for license information
7+
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
8+
9+
/// A named command line argument; either a flag or an option with a value.
10+
public struct CommandLineArgument {
11+
/// The names of this command line argument.
12+
public var names: Names
13+
/// The kind of command line argument.
14+
public var kind: Kind
15+
16+
/// A collection of names for a command line argument.
17+
public struct Names: Hashable {
18+
/// The preferred name for this command line argument.
19+
public var preferred: String
20+
/// All possible names for this command line argument.
21+
public var all: Set<String>
22+
23+
/// Creates a new command line argument collection of names.
24+
///
25+
/// - Parameters:
26+
/// - preferred: The preferred name for this command line argument.
27+
/// - alternatives: A collection of alternative names for this command line argument.
28+
public init(preferred: String, alternatives: Set<String> = []) {
29+
self.all = alternatives.union([preferred])
30+
self.preferred = preferred
31+
}
32+
}
33+
34+
/// A kind of command line argument.
35+
public enum Kind {
36+
/// A flag argument without an associated value.
37+
///
38+
/// For example: `"--some-flag"`.
39+
case flag
40+
/// An option argument with an associated value.
41+
///
42+
/// For example: `"--some-option", "value"` or `"--some-option=value"`.
43+
case option(value: String)
44+
}
45+
46+
/// Creates a new command line flag with the given names.
47+
/// - Parameters:
48+
/// - names: The names for the new command line flag.
49+
public static func flag(_ names: Names) -> Self {
50+
.init(names: names, kind: .flag)
51+
}
52+
53+
/// Creates a new command option with the given names and associated value.
54+
/// - Parameters:
55+
/// - names: The names for the new command line option.
56+
/// - value: The value that's associated with this command line option.
57+
public static func option(_ names: Names, value: String) -> Self {
58+
.init(names: names, kind: .option(value: value))
59+
}
60+
}

0 commit comments

Comments
 (0)