@@ -810,6 +810,177 @@ final class PluginInvocationTests: XCTestCase {
810810        } 
811811    } 
812812
813+     func  testPrebuildPluginShouldUseBinaryTarget( )  async  throws  { 
814+         // Only run the test if the environment in which we're running actually supports Swift concurrency (which the plugin APIs require).
815+         try XCTSkipIf ( !UserToolchain. default. supportsSwiftConcurrency ( ) ,  " skipping because test environment doesn't support concurrency " ) 
816+ 
817+         try await  testWithTemporaryDirectory  {  tmpPath in 
818+             // Create a sample package with a library target and a plugin.
819+             let  packageDir  =  tmpPath. appending ( components:  " mypkg " ) 
820+             try . createDirectory ( packageDir,  recursive:  true ) 
821+             try . writeFileContents ( packageDir. appending ( " Package.swift " ) ,  string:  """ 
822+                 // swift-tools-version:5.7 
823+ 
824+                 import PackageDescription 
825+ 
826+                 let package = Package( 
827+                     name:  " mypkg " , 
828+                     products: [ 
829+                         .library( 
830+                             name:  " MyLib " , 
831+                             targets: [ " MyLib " ]) 
832+                     ], 
833+                     targets: [ 
834+                         .target( 
835+                             name:  " MyLib " , 
836+                             plugins: [ 
837+                                 .plugin(name:  " X " ) 
838+                             ]), 
839+                         .plugin( 
840+                             name:  " X " , 
841+                             capability: .buildTool(), 
842+                             dependencies: [  " Y "  ] 
843+                         ), 
844+                         .binaryTarget( 
845+                             name:  " Y " , 
846+                             path:  " Binaries/Y. \( artifactBundleExtension) " 
847+                         ), 
848+                     ] 
849+                 ) 
850+                  """ ) 
851+ 
852+             let  libTargetDir  =  packageDir. appending ( components:  " Sources " ,  " MyLib " ) 
853+             try . createDirectory ( libTargetDir,  recursive:  true ) 
854+             try . writeFileContents ( libTargetDir. appending ( " file.swift " ) ,  string:  """ 
855+                 public struct MyUtilLib { 
856+                     public let strings: [String] 
857+                     public init(args: [String]) { 
858+                         self.strings = args 
859+                     } 
860+                 } 
861+              """ ) 
862+ 
863+             let  depTargetDir  =  packageDir. appending ( components:  " Sources " ,  " Y " ) 
864+             try . createDirectory ( depTargetDir,  recursive:  true ) 
865+             try . writeFileContents ( depTargetDir. appending ( " main.swift " ) ,  string:  """ 
866+                 struct Y { 
867+                     func run() { 
868+                         print( " You passed us two arguments, argumentOne, and argumentTwo " ) 
869+                     } 
870+                 } 
871+                 Y.main() 
872+              """ ) 
873+ 
874+             let  pluginTargetDir  =  packageDir. appending ( components:  " Plugins " ,  " X " ) 
875+             try . createDirectory ( pluginTargetDir,  recursive:  true ) 
876+             try . writeFileContents ( pluginTargetDir. appending ( " plugin.swift " ) ,  string:  """ 
877+                   import PackagePlugin 
878+                   @main struct X: BuildToolPlugin { 
879+                       func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] { 
880+                           [ 
881+                               Command.prebuildCommand( 
882+                                   displayName:  " X: Running Y before the build... " , 
883+                                   executable: try context.tool(named:  " Y " ).path, 
884+                                   arguments: [  " ARGUMENT_ONE " ,  " ARGUMENT_TWO "  ], 
885+                                   outputFilesDirectory: context.pluginWorkDirectory.appending( " OUTPUT_FILES_DIRECTORY " ) 
886+                               ) 
887+                           ] 
888+                       } 
889+                   } 
890+                    """ ) 
891+             
892+             let  artifactVariants  =  [ try UserToolchain . default. targetTriple] . map  { 
893+                 """ 
894+                 {  " path " :  " Y " ,  " supportedTriples " : [ " \( $0. tripleString) " ] } 
895+                  """ 
896+             } 
897+ 
898+             let  bundlePath  =  packageDir. appending ( components:  " Binaries " ,  " Y. \( artifactBundleExtension) " ) 
899+             let  bundleMetadataPath  =  bundlePath. appending ( component:  " info.json " ) 
900+             try . createDirectory ( bundleMetadataPath. parentDirectory,  recursive:  true ) 
901+             try . writeFileContents ( 
902+                 bundleMetadataPath, 
903+                 string:  """ 
904+                 {    " schemaVersion " :  " 1.0 " , 
905+                      " artifacts " : { 
906+                          " Y " : { 
907+                              " type " :  " executable " , 
908+                              " version " :  " 1.2.3 " , 
909+                              " variants " : [ 
910+                                  \( artifactVariants. joined ( separator:  " , " ) ) 
911+                             ] 
912+                         } 
913+                     } 
914+                 } 
915+                  """ 
916+             ) 
917+             let  binaryPath  =  bundlePath. appending ( component:  " Y " ) 
918+             try . writeFileContents ( binaryPath,  string:  " " ) 
919+ 
920+             // Load a workspace from the package.
921+             let  observability  =  ObservabilitySystem . makeForTesting ( ) 
922+             let  workspace  =  try Workspace ( 
923+                 fileSystem:  localFileSystem, 
924+                 forRootPackage:  packageDir, 
925+                 customManifestLoader:  ManifestLoader ( toolchain:  UserToolchain . default) , 
926+                 delegate:  MockWorkspaceDelegate ( ) 
927+             ) 
928+ 
929+             // Load the root manifest.
930+             let  rootInput  =  PackageGraphRootInput ( packages:  [ packageDir] ,  dependencies:  [ ] ) 
931+             let  rootManifests  =  try await  workspace. loadRootManifests ( 
932+                 packages:  rootInput. packages, 
933+                 observabilityScope:  observability. topScope
934+             ) 
935+             XCTAssert ( rootManifests. count ==  1 ,  " \( rootManifests) " ) 
936+ 
937+             // Load the package graph.
938+             let  packageGraph  =  try await  workspace. loadPackageGraph ( 
939+                 rootInput:  rootInput, 
940+                 observabilityScope:  observability. topScope
941+             ) 
942+             XCTAssertNoDiagnostics ( observability. diagnostics) 
943+             XCTAssert ( packageGraph. packages. count ==  1 ,  " \( packageGraph. packages) " ) 
944+ 
945+             // Find the build tool plugin.
946+             let  buildToolPlugin  =  try XCTUnwrap ( packageGraph. packages. first? . modules. map ( \. underlying) . filter {  $0. name ==  " X "  } . first as?  PluginModule ) 
947+             XCTAssertEqual ( buildToolPlugin. name,  " X " ) 
948+             XCTAssertEqual ( buildToolPlugin. capability,  . buildTool) 
949+ 
950+             // Create a plugin script runner for the duration of the test.
951+             let  pluginCacheDir  =  tmpPath. appending ( " plugin-cache " ) 
952+             let  pluginScriptRunner  =  DefaultPluginScriptRunner ( 
953+                 fileSystem:  localFileSystem, 
954+                 cacheDir:  pluginCacheDir, 
955+                 toolchain:  try UserToolchain . default
956+             ) 
957+ 
958+             // Invoke build tool plugin
959+             do  { 
960+                 let  outputDir  =  packageDir. appending ( " .build " ) 
961+                 let  buildParameters  =  mockBuildParameters ( 
962+                     destination:  . host, 
963+                     environment:  BuildEnvironment ( platform:  . macOS,  configuration:  . debug) 
964+                 ) 
965+ 
966+                 let  result  =  try await  invokeBuildToolPlugins ( 
967+                     graph:  packageGraph, 
968+                     buildParameters:  buildParameters, 
969+                     fileSystem:  localFileSystem, 
970+                     outputDir:  outputDir, 
971+                     pluginScriptRunner:  pluginScriptRunner, 
972+                     observabilityScope:  observability. topScope
973+                 ) 
974+ 
975+                 let  diags  =  result. flatMap ( \. value. results) . flatMap ( \. diagnostics) 
976+                 testDiagnostics ( diags)  {  result in 
977+                     result. checkIsEmpty ( ) 
978+                 } 
979+             } 
980+         } 
981+     } 
982+ 
983+ 
813984    func  testPrebuildPluginShouldNotUseExecTarget( )  async  throws  { 
814985        // Only run the test if the environment in which we're running actually supports Swift concurrency (which the plugin APIs require).
815986        try XCTSkipIf ( !UserToolchain. default. supportsSwiftConcurrency ( ) ,  " skipping because test environment doesn't support concurrency " ) 
@@ -1203,7 +1374,7 @@ final class PluginInvocationTests: XCTestCase {
12031374            try . writeFileContents ( myPluginTargetDir. appending ( " plugin.swift " ) ,  string:  content) 
12041375            let  artifactVariants  =  artifactSupportedTriples. map  { 
12051376                """ 
1206-                 {  " path " :  " LocalBinaryTool \( $0. tripleString) .sh " ,  " supportedTriples " : [ " \( $0. tripleString) " ] } 
1377+                 {  " path " :  " \( $0. tripleString) /LocalBinaryTool " ,  " supportedTriples " : [ " \( $0. tripleString) " ] } 
12071378                 """ 
12081379            } 
12091380
@@ -1339,7 +1510,7 @@ final class PluginInvocationTests: XCTestCase {
13391510            $0. value. forEach  { 
13401511                XCTAssertTrue ( $0. succeeded,  " plugin unexpectedly failed " ) 
13411512                XCTAssertEqual ( $0. diagnostics. map  {  $0. message } ,  [ ] ,  " plugin produced unexpected diagnostics " ) 
1342-                 XCTAssertEqual ( $0. buildCommands. first? . configuration. executable. basename,  " LocalBinaryTool \( hostTriple . tripleString ) .sh " ) 
1513+                 XCTAssertEqual ( $0. buildCommands. first? . configuration. executable. basename,  " LocalBinaryTool " ) 
13431514            } 
13441515        } 
13451516    } 
0 commit comments