@@ -904,6 +904,66 @@ extension BuildPlan {
904
904
extension BuildPlan {
905
905
fileprivate typealias Destination = BuildParameters . Destination
906
906
907
+ fileprivate enum TraversalNode : Hashable {
908
+ case package ( ResolvedPackage )
909
+ case product( ResolvedProduct , BuildParameters . Destination )
910
+ case module( ResolvedModule , BuildParameters . Destination )
911
+
912
+ var destination : BuildParameters . Destination {
913
+ switch self {
914
+ case . package :
915
+ . target
916
+ case . product( _, let destination) :
917
+ destination
918
+ case . module( _, let destination) :
919
+ destination
920
+ }
921
+ }
922
+
923
+ static func `for`(
924
+ product: ResolvedProduct ,
925
+ context destination: BuildParameters . Destination
926
+ ) -> Self {
927
+ switch product. type {
928
+ case . macro, . plugin:
929
+ . product( product, . host)
930
+ case . test:
931
+ . product( product, product. modules. contains ( where: self . hasMacroDependency) ? . host : destination)
932
+ default :
933
+ . product( product, destination)
934
+ }
935
+ }
936
+
937
+ static func `for`(
938
+ module: ResolvedModule ,
939
+ context destination: BuildParameters . Destination
940
+ ) -> Self {
941
+ switch module. type {
942
+ case . macro, . plugin:
943
+ // Macros and plugins are ways built for host
944
+ . module( module, . host)
945
+ case . test:
946
+ . module( module, self . hasMacroDependency ( module: module) ? . host : destination)
947
+ default :
948
+ // By default assume the destination of the context.
949
+ // This means that i.e. test products that reference macros
950
+ // would force all of their successors to be `host`
951
+ . module( module, destination)
952
+ }
953
+ }
954
+
955
+ static func hasMacroDependency( module: ResolvedModule ) -> Bool {
956
+ module. dependencies. contains ( where: {
957
+ switch $0 {
958
+ case . product( let productDependency, _) :
959
+ productDependency. type == . macro
960
+ case . module( let moduleDependency, _) :
961
+ moduleDependency. type == . macro
962
+ }
963
+ } )
964
+ }
965
+ }
966
+
907
967
/// Traverse the modules graph and find a destination for every product and module.
908
968
/// All non-macro/plugin products and modules have `target` destination with one
909
969
/// notable exception - test products/modules with direct macro dependency.
@@ -912,57 +972,8 @@ extension BuildPlan {
912
972
onProduct: ( ResolvedProduct , Destination ) throws -> Void ,
913
973
onModule: ( ResolvedModule , Destination ) async throws -> Void
914
974
) async rethrows {
915
- enum Node : Hashable {
916
- case package ( ResolvedPackage )
917
- case product( ResolvedProduct , Destination )
918
- case module( ResolvedModule , Destination )
919
-
920
- static func `for`(
921
- product: ResolvedProduct ,
922
- context destination: Destination
923
- ) -> Node {
924
- switch product. type {
925
- case . macro, . plugin:
926
- . product( product, . host)
927
- case . test:
928
- . product( product, product. modules. contains ( where: self . hasMacroDependency) ? . host : destination)
929
- default :
930
- . product( product, destination)
931
- }
932
- }
933
-
934
- static func `for`(
935
- module: ResolvedModule ,
936
- context destination: Destination
937
- ) -> Node {
938
- switch module. type {
939
- case . macro, . plugin:
940
- // Macros and plugins are ways built for host
941
- . module( module, . host)
942
- case . test:
943
- . module( module, self . hasMacroDependency ( module: module) ? . host : destination)
944
- default :
945
- // By default assume the destination of the context.
946
- // This means that i.e. test products that reference macros
947
- // would force all of their successors to be `host`
948
- . module( module, destination)
949
- }
950
- }
951
-
952
- static func hasMacroDependency( module: ResolvedModule ) -> Bool {
953
- module. dependencies. contains ( where: {
954
- switch $0 {
955
- case . product( let productDependency, _) :
956
- productDependency. type == . macro
957
- case . module( let moduleDependency, _) :
958
- moduleDependency. type == . macro
959
- }
960
- } )
961
- }
962
- }
963
-
964
- func successors( for package : ResolvedPackage ) -> [ Node ] {
965
- var successors : [ Node ] = [ ]
975
+ func successors( for package : ResolvedPackage ) -> [ TraversalNode ] {
976
+ var successors : [ TraversalNode ] = [ ]
966
977
for product in package . products {
967
978
if case . test = product. underlying. type,
968
979
!graph. rootPackages. contains ( id: package . id)
@@ -989,7 +1000,7 @@ extension BuildPlan {
989
1000
func successors(
990
1001
for product: ResolvedProduct ,
991
1002
destination: Destination
992
- ) -> [ Node ] {
1003
+ ) -> [ TraversalNode ] {
993
1004
guard destination == . host else {
994
1005
return [ ]
995
1006
}
@@ -1002,12 +1013,12 @@ extension BuildPlan {
1002
1013
func successors(
1003
1014
for module: ResolvedModule ,
1004
1015
destination: Destination
1005
- ) -> [ Node ] {
1016
+ ) -> [ TraversalNode ] {
1006
1017
guard destination == . host else {
1007
1018
return [ ]
1008
1019
}
1009
1020
1010
- return module. dependencies. reduce ( into: [ Node ] ( ) ) { partial, dependency in
1021
+ return module. dependencies. reduce ( into: [ TraversalNode ] ( ) ) { partial, dependency in
1011
1022
switch dependency {
1012
1023
case . product( let product, conditions: _) :
1013
1024
partial. append ( . for( product: product, context: destination) )
@@ -1017,7 +1028,7 @@ extension BuildPlan {
1017
1028
}
1018
1029
}
1019
1030
1020
- try await depthFirstSearch ( graph. packages. map { Node . package ( $0) } ) { node in
1031
+ try await depthFirstSearch ( graph. packages. map { TraversalNode . package ( $0) } ) { node in
1021
1032
switch node {
1022
1033
case . package ( let package ) :
1023
1034
successors ( for: package )
@@ -1040,6 +1051,71 @@ extension BuildPlan {
1040
1051
// No de-duplication is necessary we only want unique nodes.
1041
1052
}
1042
1053
}
1054
+
1055
+ /// Traverses the modules graph, computes destination of every module reference and
1056
+ /// provides the data to the caller by means of `onModule` callback. The products
1057
+ /// are completely transparent to this method and are represented by their module dependencies.
1058
+ package func traverseModules(
1059
+ _ onModule: (
1060
+ ( ResolvedModule , BuildParameters . Destination ) ,
1061
+ _ parent: ( ResolvedModule , BuildParameters . Destination ) ? ,
1062
+ _ depth: Int
1063
+ ) -> Void
1064
+ ) {
1065
+ func successors( for package : ResolvedPackage ) -> [ TraversalNode ] {
1066
+ package . modules. compactMap {
1067
+ if case . test = $0. underlying. type,
1068
+ !self . graph. rootPackages. contains ( id: package . id)
1069
+ {
1070
+ return nil
1071
+ }
1072
+ return . for( module: $0, context: . target)
1073
+ }
1074
+ }
1075
+
1076
+ func successors(
1077
+ for module: ResolvedModule ,
1078
+ destination: Destination
1079
+ ) -> [ TraversalNode ] {
1080
+ module. dependencies. reduce ( into: [ TraversalNode] ( ) ) { partial, dependency in
1081
+ switch dependency {
1082
+ case . product( let product, conditions: _) :
1083
+ let parent : TraversalNode = . for( product: product, context: destination)
1084
+ for module in product. modules {
1085
+ partial. append ( . for( module: module, context: parent. destination) )
1086
+ }
1087
+ case . module( let module, _) :
1088
+ partial. append ( . for( module: module, context: destination) )
1089
+ }
1090
+ }
1091
+ }
1092
+
1093
+ depthFirstSearch ( self . graph. packages. map { TraversalNode . package ( $0) } ) {
1094
+ switch $0 {
1095
+ case . package ( let package ) :
1096
+ successors ( for: package )
1097
+ case . module( let module, let destination) :
1098
+ successors ( for: module, destination: destination)
1099
+ case . product:
1100
+ [ ]
1101
+ }
1102
+ } onNext: { current, parent, depth in
1103
+ let parentModule : ( ResolvedModule , BuildParameters . Destination ) ? = switch parent {
1104
+ case . package , . product, nil :
1105
+ nil
1106
+ case . module( let module, let destination) :
1107
+ ( module, destination)
1108
+ }
1109
+
1110
+ switch current {
1111
+ case . package , . product:
1112
+ break
1113
+
1114
+ case . module( let module, let destination) :
1115
+ onModule ( ( module, destination) , parentModule, depth)
1116
+ }
1117
+ }
1118
+ }
1043
1119
}
1044
1120
1045
1121
extension Basics . Diagnostic {
0 commit comments