@@ -199,32 +199,6 @@ private func checkAllDependenciesAreUsed(_ rootPackages: [ResolvedPackage], obse
199
199
}
200
200
}
201
201
202
- extension Package {
203
- // Add module aliases specified for applicable targets
204
- fileprivate func setModuleAliasesForTargets( with moduleAliasMap: [ String : [ ModuleAliasModel ] ] ) {
205
- // Set module aliases for each target's dependencies
206
- for target in self . targets {
207
- let aliasesForTarget = moduleAliasMap. filter { $0. key == target. name} . values. flatMap { $0}
208
- for entry in aliasesForTarget {
209
- if entry. name != target. name {
210
- target. addModuleAlias ( for: entry. name, as: entry. alias)
211
- }
212
- }
213
- }
214
-
215
- // This loop should run after the loop above as it may rename the target
216
- // as an alias if specified
217
- for target in self . targets {
218
- let aliasesForTarget = moduleAliasMap. filter { $0. key == target. name} . values. flatMap { $0}
219
- for entry in aliasesForTarget {
220
- if entry. name == target. name {
221
- target. addModuleAlias ( for: entry. name, as: entry. alias)
222
- }
223
- }
224
- }
225
- }
226
- }
227
-
228
202
fileprivate extension ResolvedProduct {
229
203
/// Returns true if and only if the product represents a command plugin target.
230
204
var isCommandPlugin : Bool {
@@ -270,9 +244,9 @@ private func createResolvedPackages(
270
244
return ( $0. package . identity, $0)
271
245
}
272
246
273
- // Gather and resolve module aliases specified for targets in all dependent packages
274
- let packageAliases = try resolveModuleAliases ( packageBuilders : packageBuilders ,
275
- observabilityScope : observabilityScope )
247
+ // Resolve module aliases, if specified, for targets and their dependencies
248
+ // across packages. Aliasing will result in target renaming.
249
+ try resolveModuleAliases ( packageBuilders : packageBuilders )
276
250
277
251
// Scan and validate the dependencies
278
252
for packageBuilder in packageBuilders {
@@ -283,10 +257,6 @@ private func createResolvedPackages(
283
257
metadata: package . diagnosticsMetadata
284
258
)
285
259
286
- if let aliasMap = packageAliases ? [ package . identity] {
287
- package . setModuleAliasesForTargets ( with: aliasMap)
288
- }
289
-
290
260
var dependencies = OrderedCollections . OrderedDictionary < PackageIdentity , ResolvedPackageBuilder > ( )
291
261
var dependenciesByNameForTargetDependencyResolution = [ String: ResolvedPackageBuilder] ( )
292
262
@@ -620,8 +590,7 @@ private func computePlatforms(
620
590
}
621
591
622
592
// Track and override module aliases specified for targets in a package graph
623
- private func resolveModuleAliases( packageBuilders: [ ResolvedPackageBuilder ] ,
624
- observabilityScope: ObservabilityScope ) throws -> [ PackageIdentity : [ String : [ ModuleAliasModel ] ] ] ? {
593
+ private func resolveModuleAliases( packageBuilders: [ ResolvedPackageBuilder ] ) throws {
625
594
626
595
// If there are no module aliases specified, return early
627
596
let hasAliases = packageBuilders. contains { $0. package . targets. contains {
@@ -634,40 +603,18 @@ private func resolveModuleAliases(packageBuilders: [ResolvedPackageBuilder],
634
603
}
635
604
}
636
605
637
- guard hasAliases else { return nil }
606
+ guard hasAliases else { return }
638
607
let aliasTracker = ModuleAliasTracker ( )
639
608
for packageBuilder in packageBuilders {
640
- for target in packageBuilder. package . targets {
641
- for dep in target. dependencies {
642
- if case let . product( prodRef, _) = dep,
643
- let prodPkg = prodRef. package {
644
- let prodPkgID = PackageIdentity . plain ( prodPkg)
645
- // Track package ID dependency chain
646
- aliasTracker. addPackageIDChain ( parent: packageBuilder. package . identity, child: prodPkgID)
647
-
648
- if let aliasList = prodRef. moduleAliases {
649
- for (depName, depAlias) in aliasList {
650
- // Track aliases for this product
651
- try aliasTracker. addAlias ( depAlias,
652
- target: depName,
653
- product: prodRef. name,
654
- originPackage: PackageIdentity . plain ( prodPkg) ,
655
- consumingPackage: packageBuilder. package . identity)
656
- }
657
- }
658
- }
659
- }
660
- }
609
+ try aliasTracker. addTargetAliases ( targets: packageBuilder. package . targets,
610
+ package : packageBuilder. package . identity)
661
611
}
662
612
663
613
// Track targets that need module aliases for each package
664
614
for packageBuilder in packageBuilders {
665
615
for product in packageBuilder. package . products {
666
- var allTargets = product. targets. map { $0. dependencies} . flatMap { $0} . compactMap { $0. target}
667
- allTargets. append ( contentsOf: product. targets)
668
- aliasTracker. addAliasesForTargets ( allTargets,
669
- product: product. name,
670
- package : packageBuilder. package . identity)
616
+ aliasTracker. trackTargetsPerProduct ( product: product,
617
+ package : packageBuilder. package . identity)
671
618
}
672
619
}
673
620
@@ -679,46 +626,67 @@ private func resolveModuleAliases(packageBuilders: [ResolvedPackageBuilder],
679
626
// upstream can be overriden.
680
627
for packageBuilder in packageBuilders {
681
628
for product in packageBuilder. package . products {
682
- var allTargets = product. targets. map { $0. dependencies} . flatMap { $0} . compactMap { $0. target}
683
- allTargets. append ( contentsOf: product. targets)
684
- try aliasTracker. validateSources ( allTargets,
685
- product: product. name,
686
- package : packageBuilder. package . identity)
629
+ try aliasTracker. validateAndApplyAliases ( product: product. name,
630
+ package : packageBuilder. package . identity)
687
631
}
688
632
}
689
-
690
- return aliasTracker. idTargetToAliases
691
633
}
692
634
693
635
// This class helps track module aliases in a package graph and override
694
636
// upstream alises if needed
695
637
private class ModuleAliasTracker {
696
638
var aliasMap = [ PackageIdentity: [ String: [ ModuleAliasModel] ] ] ( )
697
- var idTargetToAliases = [ PackageIdentity: [ String: [ ModuleAliasModel] ] ] ( )
639
+ var idToProductToAllTargets = [ PackageIdentity: [ String: [ Target] ] ] ( )
640
+ var productToDirectTargets = [ String: [ Target] ] ( )
641
+ var productToAllTargets = [ String: [ Target] ] ( )
642
+ var childToParentProducts = [ String: [ String] ] ( )
643
+ var cachedChildToParentProducts = [ String: [ String] ] ( )
698
644
var parentToChildIDs = [ PackageIdentity: [ PackageIdentity] ] ( )
699
645
var childToParentID = [ PackageIdentity: PackageIdentity] ( )
700
646
701
647
init ( ) { }
648
+ func addTargetAliases( targets: [ Target ] , package : PackageIdentity ) throws {
649
+ let targetDependencies = targets. map { $0. dependencies} . flatMap { $0}
650
+ for dep in targetDependencies {
651
+ if case let . product( productRef, _) = dep,
652
+ let productPkg = productRef. package {
653
+ let productPkgID = PackageIdentity . plain ( productPkg)
654
+ // Track dependency package ID chain
655
+ addPackageIDChain ( parent: package , child: productPkgID)
656
+ if let aliasList = productRef. moduleAliases {
657
+ // Track aliases for this product
658
+ try addAliases ( aliasList,
659
+ product: productRef. name,
660
+ originPackage: productPkgID,
661
+ consumingPackage: package )
662
+ }
663
+ }
664
+ }
665
+ }
702
666
703
- func addAlias( _ alias: String ,
704
- target: String ,
705
- product: String ,
706
- originPackage: PackageIdentity ,
707
- consumingPackage: PackageIdentity ) throws {
667
+ func addAliases( _ aliases: [ String : String ] ,
668
+ product: String ,
669
+ originPackage: PackageIdentity ,
670
+ consumingPackage: PackageIdentity ) throws {
708
671
if let aliasDict = aliasMap [ originPackage] {
709
- let models = aliasDict. values. flatMap { $0} . filter { $0. name == target }
710
- if !models. isEmpty {
711
- // Error if there are multiple aliases specified for this product dependency
712
- throw PackageGraphError . multipleModuleAliases ( target: target, product: product, package : originPackage. description, aliases: models. map { $0. alias} + [ alias] )
672
+ let existingAliases = aliasDict. values. flatMap { $0} . filter { aliases. keys. contains ( $0. name) }
673
+ for existingAlias in existingAliases {
674
+ if let newAlias = aliases [ existingAlias. name] , newAlias != existingAlias. alias {
675
+ // Error if there are multiple different aliases specified for
676
+ // targets in this product
677
+ throw PackageGraphError . multipleModuleAliases ( target: existingAlias. name, product: product, package : originPackage. description, aliases: existingAliases. map { $0. alias} + [ newAlias] )
678
+ }
713
679
}
714
680
}
715
681
716
- let model = ModuleAliasModel ( name: target, alias: alias, originPackage: originPackage, consumingPackage: consumingPackage)
717
- aliasMap [ originPackage, default: [ : ] ] [ product, default: [ ] ] . append ( model)
682
+ for (originalName, newName) in aliases {
683
+ let model = ModuleAliasModel ( name: originalName, alias: newName, originPackage: originPackage, consumingPackage: consumingPackage)
684
+ aliasMap [ originPackage, default: [ : ] ] [ product, default: [ ] ] . append ( model)
685
+ }
718
686
}
719
687
720
688
func addPackageIDChain( parent: PackageIdentity ,
721
- child: PackageIdentity ) {
689
+ child: PackageIdentity ) {
722
690
if parentToChildIDs [ parent] ? . contains ( child) ?? false {
723
691
// Already added
724
692
} else {
@@ -728,30 +696,31 @@ private class ModuleAliasTracker {
728
696
}
729
697
}
730
698
731
- func addAliasesForTargets( _ targets: [ Target ] ,
732
- product: String ,
733
- package : PackageIdentity ) {
734
- let aliases = aliasMap [ package ] ? [ product]
735
- for target in targets {
736
- if idTargetToAliases [ package ] ? [ target. name] == nil {
737
- idTargetToAliases [ package , default: [ : ] ] [ target. name] = [ ]
738
- }
739
-
740
- if let aliases = aliases {
741
- idTargetToAliases [ package ] ? [ target. name] ? . append ( contentsOf: aliases)
699
+ // This func should be called once per product
700
+ func trackTargetsPerProduct( product: Product ,
701
+ package : PackageIdentity ) {
702
+ let productTargetDeps = product. targets. map { $0. dependencies} . flatMap { $0}
703
+ for dep in productTargetDeps {
704
+ if case let . product( depRef, _) = dep {
705
+ childToParentProducts [ depRef. name, default: [ ] ] . append ( product. name)
742
706
}
743
707
}
708
+ var allTargets = productTargetDeps. compactMap { $0. target}
709
+ allTargets. append ( contentsOf: product. targets)
710
+ idToProductToAllTargets [ package , default: [ : ] ] [ product. name] = allTargets
711
+ productToDirectTargets [ product. name] = product. targets
712
+ productToAllTargets [ product. name] = allTargets
744
713
}
745
714
746
- func validateSources( _ targets: [ Target ] ,
747
- product: String ,
748
- package : PackageIdentity ) throws {
749
- for target in targets {
750
- if let aliases = idTargetToAliases [ package ] ? [ target. name] , !aliases. isEmpty {
751
- if target. sources. containsNonSwiftFiles {
752
- throw PackageGraphError . invalidSourcesForModuleAliasing ( target: target. name, product: product, package : package . description)
753
- }
715
+ func validateAndApplyAliases( product: String ,
716
+ package : PackageIdentity ) throws {
717
+ guard let targets = idToProductToAllTargets [ package ] ? [ product] else { return }
718
+ let targetsWithAliases = targets. filter { $0. moduleAliases != nil }
719
+ for target in targetsWithAliases {
720
+ if target. sources. containsNonSwiftFiles {
721
+ throw PackageGraphError . invalidSourcesForModuleAliasing ( target: target. name, product: product, package : package . description)
754
722
}
723
+ target. applyAlias ( )
755
724
}
756
725
}
757
726
@@ -764,34 +733,90 @@ private class ModuleAliasTracker {
764
733
// pkgID is not nil here so can be force unwrapped
765
734
pkgID = childToParentID [ pkgID!]
766
735
}
767
-
768
736
guard let rootPkg = rootPkg else { return }
769
- propagate ( from: rootPkg)
737
+ var aliasBuffer = [ String: ModuleAliasModel] ( )
738
+ var targetBuffer = [ Target] ( )
739
+ propagate ( package : rootPkg, parent: nil , targetBuffer: & targetBuffer, aliasBuffer: & aliasBuffer)
770
740
}
771
741
772
- func propagate( from cur: PackageIdentity ) {
773
- guard let children = parentToChildIDs [ cur] else { return }
774
- for child in children {
775
- if let parentMap = idTargetToAliases [ cur] ,
776
- let childMap = idTargetToAliases [ child] {
777
- for (_, parentAliases) in parentMap {
778
- for parentModel in parentAliases {
779
- for (childTarget, childAliases) in childMap {
780
- if !parentMap. keys. contains ( childTarget) ,
781
- childTarget == parentModel. name {
782
- if childAliases. isEmpty {
783
- idTargetToAliases [ child] ? [ childTarget] ? . append ( parentModel)
784
- } else {
785
- for childModel in childAliases {
786
- childModel. alias = parentModel. alias
742
+ func propagate( package : PackageIdentity , parent: PackageIdentity ? , targetBuffer: inout [ Target ] , aliasBuffer: inout [ String : ModuleAliasModel ] ) {
743
+ if let curProductToTargetAliases = aliasMap [ package ] {
744
+ let curAliasModels = curProductToTargetAliases. map { $0. value} . filter { !$0. isEmpty} . flatMap { $0}
745
+ for aliasModel in curAliasModels {
746
+ // A buffer is used to track the most downstream aliases
747
+ // (hence the nil check here) to allow overriding upstream
748
+ // aliases for targets; if the downstream aliases are applied
749
+ // to upstream targets, then they get removed
750
+ if aliasBuffer [ aliasModel. name] == nil {
751
+ // Add a target name as a key. The buffer only tracks
752
+ // a target that needs to be renamed, not the depending
753
+ // targets which might have multiple target dependencies
754
+ // with their aliases, so add a single alias model as value.
755
+ aliasBuffer [ aliasModel. name] = aliasModel
756
+ }
757
+ }
758
+ }
759
+ if let curProductToTargets = idToProductToAllTargets [ package ] {
760
+ // Check if targets for the products in this package have
761
+ // aliases tracked by the buffer
762
+ let curProductToTargetsWithAliases = curProductToTargets. filter { $0. value. contains { aliasBuffer [ $0. name] != nil } }
763
+ if !curProductToTargetsWithAliases. isEmpty {
764
+ var usedKeys = [ String] ( )
765
+ for (curProductName, targetsForCurProduct) in curProductToTargets {
766
+ if let commonAliasesForTargets = curProductToTargetsWithAliases [ curProductName] ,
767
+ let nameKey = commonAliasesForTargets. first? . name,
768
+ let aliasModel = aliasBuffer [ nameKey] {
769
+ for curTarget in targetsForCurProduct {
770
+ curTarget. addModuleAlias ( for: aliasModel. name, as: aliasModel. alias)
771
+ }
772
+ // Once adding aliases for targets in this product, need to
773
+ // add them to targets in the parent product since they can
774
+ // import the now aliased targets
775
+ var parentProducts = [ String] ( )
776
+ gatherParentProducts ( curProductName, result: & parentProducts)
777
+ for parentProduct in parentProducts {
778
+ let hasConflictWithAlias = productToAllTargets [ parentProduct] ? . contains { $0. name == aliasModel. name } ?? false
779
+ // if conflicting, parent target will need to
780
+ // directly import the child target that's renamed
781
+ if !hasConflictWithAlias {
782
+ let targetsToAlias = productToDirectTargets [ parentProduct] ? . filter { targetArg in
783
+ if let aliases = targetArg. moduleAliases {
784
+ // if already aliased, should not override
785
+ return aliases [ aliasModel. name] == nil
787
786
}
787
+ return true
788
+ } ?? [ ]
789
+ for parentTarget in targetsToAlias {
790
+ parentTarget. addModuleAlias ( for: aliasModel. name, as: aliasModel. alias)
788
791
}
789
792
}
790
793
}
794
+ usedKeys. append ( nameKey)
791
795
}
792
796
}
797
+ for used in usedKeys {
798
+ // Remove an entry for a used alias
799
+ aliasBuffer. removeValue ( forKey: used)
800
+ }
801
+ }
802
+ }
803
+ guard let children = parentToChildIDs [ package ] else { return }
804
+ for childID in children {
805
+ propagate ( package : childID, parent: package , targetBuffer: & targetBuffer, aliasBuffer: & aliasBuffer)
806
+ }
807
+ }
808
+
809
+ func gatherParentProducts( _ productName: String , result: inout [ String ] ) {
810
+ if let cached = cachedChildToParentProducts [ productName] {
811
+ result. append ( contentsOf: cached)
812
+ return
813
+ }
814
+ if let parents = childToParentProducts [ productName] {
815
+ result. append ( contentsOf: parents)
816
+ cachedChildToParentProducts [ productName, default: [ ] ] . append ( contentsOf: parents)
817
+ for parentProd in parents {
818
+ gatherParentProducts ( parentProd, result: & result)
793
819
}
794
- propagate ( from: child)
795
820
}
796
821
}
797
822
}
0 commit comments