@@ -253,35 +253,33 @@ struct GenerateDocumentation: AsyncSwiftCommand {
253253 let doccExecutable = try swiftCommandState. toolsBuildParameters. toolchain. toolchainDir. appending ( components: [ " usr " , " bin " , " docc " ] )
254254
255255 var modules : [ ResolvedModule ] = [ ]
256+ var products : [ ResolvedProduct ] = [ ]
256257
257258 // Copy the symbol graphs from the target-specific locations to the single output directory
258259 for rootPackage in try await buildSystem. getPackageGraph ( ) . rootPackages {
259260 if !internalDocs {
260261 for product in rootPackage. products {
261- modules. append ( contentsOf: product. modules)
262+ for module in product. modules {
263+ modules. append ( module)
264+ }
265+
266+ products. append ( product)
262267 }
263268 } else {
264269 modules. append ( contentsOf: rootPackage. modules)
265270 }
266271 }
267272
268- for module: ResolvedModule in modules {
269- // TODO handle executable modules differently using a command-line reference generator
270- guard module. type != . test && module. type != . plugin else {
271- continue
272- }
273+ for product in products {
274+ if product. type == . executable {
275+ let exec = builtArtifacts. filter ( { $0. 1 . kind == . executable && $0. 0 == " \( product. name) -product " } ) . first? . 1 . path
273276
274- if module . type == . executable {
275- // TODO check on the tuple filtering based on the module name here
276- // FIXME executables are at the product level, not the module level, this needs to be redone to fit that model
277- let exec = builtArtifacts . filter ( { $0 . 0 == " \( module . name . lowercased ( ) ) -product " } ) . map ( { $0 . 1 . path } ) . first
277+ guard let exec else {
278+ print ( " Couldn't find \( product . name) " )
279+ continue
280+ }
278281
279- guard let exec else {
280- print ( " Couldn't find \( module. name) " )
281- continue
282- }
283-
284- do {
282+ do {
285283 // FIXME run the executable within a very restricted sandbox
286284 let dumpHelpProcess = AsyncProcess ( args: [ exec, " --experimental-dump-help " ] , outputRedirection: . collect)
287285 try dumpHelpProcess. launch ( )
@@ -293,23 +291,23 @@ struct GenerateDocumentation: AsyncSwiftCommand {
293291
294292 // Creating a simple DocC catalog
295293 // TODO copy over an existing DocC catalog for this module if one exists already
296- let catalogDir = buildPath. appending ( components: [ " tool-docc-catalog " , module . name, " Documentation.docc " ] )
294+ let catalogDir = buildPath. appending ( components: [ " tool-docc-catalog " , product . name, " Documentation.docc " ] )
297295 try ? swiftCommandState. fileSystem. removeFileTree ( catalogDir)
298296 try swiftCommandState. fileSystem. createDirectory ( catalogDir, recursive: true )
299- let summaryMd = catalogDir. appending ( components: [ " \( module . name. lowercased ( ) ) .md " ] )
297+ let summaryMd = catalogDir. appending ( components: [ " \( product . name. lowercased ( ) ) .md " ] )
300298 try swiftCommandState. fileSystem. writeFileContents ( summaryMd, string: page)
301299
302- let archiveDir = buildPath. appending ( components: [ " tool-docc-archive " , " \( module . name) .doccarchive " ] )
300+ let archiveDir = buildPath. appending ( components: [ " tool-docc-archive " , " \( product . name) .doccarchive " ] )
303301 try ? swiftCommandState. fileSystem. removeFileTree ( archiveDir)
304302 try swiftCommandState. fileSystem. createDirectory ( archiveDir. parentDirectory, recursive: true )
305303
306- print ( " CONVERT TOOL: \( module . name) " )
304+ print ( " CONVERT TOOL: \( product . name) " )
307305
308306 let process = try Process . run ( URL ( fileURLWithPath: doccExecutable. pathString) , arguments: [
309307 " convert " ,
310308 catalogDir. pathString,
311- " --fallback-display-name= \( module . name) " ,
312- " --fallback-bundle-identifier= \( module . name) " ,
309+ " --fallback-display-name= \( product . name) " ,
310+ " --fallback-bundle-identifier= \( product . name) " ,
313311 " --output-path= \( archiveDir) " ,
314312 ] )
315313 process. waitUntilExit ( )
@@ -318,15 +316,25 @@ struct GenerateDocumentation: AsyncSwiftCommand {
318316 doccArchives. append ( archiveDir. pathString)
319317 }
320318 } catch {
321- print ( " warning: could not generate tool info documentation for \( module . name) " )
319+ print ( " warning: could not generate tool info documentation for \( product . name) " )
322320 }
323321
324322 continue
325323 }
326-
324+ }
325+
326+ for module : ResolvedModule in modules {
327+ guard module. type != . test && module. type != . plugin && module. type != . executable else {
328+ continue
329+ }
327330
328331 let inputPathDir = symbolGraph. outputLocationForTarget ( module. name, try swiftCommandState. productsBuildParameters)
329332 let inputPath = buildPath. appending ( components: inputPathDir)
333+
334+ guard swiftCommandState. fileSystem. exists ( inputPath) else {
335+ continue
336+ }
337+
330338 let outputPathDir = [ String] ( inputPathDir. dropLast ( ) ) + [ inputPathDir. last!. replacing ( " .symbolgraphs " , with: " .doccarchive " ) ]
331339 let outputPath = buildPath. appending ( components: outputPathDir)
332340
@@ -338,6 +346,8 @@ struct GenerateDocumentation: AsyncSwiftCommand {
338346 let catalogArgs = if let doccCatalog { [ doccCatalog. pathString] } else { [ String] ( ) }
339347
340348 print ( " CONVERT: \( module. name) " )
349+
350+ print ( " docc convert \( catalogArgs. joined ( separator: " " ) ) \( [ " --fallback-display-name= \( module. name) " , " --fallback-bundle-identifier= \( module. name) " , " --additional-symbol-graph-dir= \( inputPath) " , " --output-path= \( outputPath) " ] . joined ( separator: " " ) ) " )
341351
342352 let process = try Process . run ( URL ( fileURLWithPath: doccExecutable. pathString) , arguments: [
343353 " convert " ,
0 commit comments