@@ -31,6 +31,7 @@ import { Sanitizer } from "./Sanitizer";
31
31
interface InfoPlist {
32
32
DefaultProperties : {
33
33
XCTEST_VERSION : string | undefined ;
34
+ SWIFT_TESTING_VERSION : string | undefined ;
34
35
} ;
35
36
}
36
37
@@ -50,6 +51,7 @@ interface SwiftTargetInfo {
50
51
compilerVersion : string ;
51
52
target ?: {
52
53
triple : string ;
54
+ unversionedTriple : string ;
53
55
[ name : string ] : string | string [ ] ;
54
56
} ;
55
57
paths : {
@@ -97,18 +99,22 @@ export function getDarwinTargetTriple(target: DarwinCompatibleTarget): string |
97
99
}
98
100
99
101
export class SwiftToolchain {
102
+ public swiftVersionString : string ;
103
+
100
104
constructor (
101
105
public swiftFolderPath : string , // folder swift executable in $PATH was found in
102
106
public toolchainPath : string , // toolchain folder. One folder up from swift bin folder. This is to support toolchains without usr folder
103
- public swiftVersionString : string , // Swift version as a string, including description
107
+ private targetInfo : SwiftTargetInfo ,
104
108
public swiftVersion : Version , // Swift version as semVar variable
105
109
public runtimePath ?: string , // runtime library included in output from `swift -print-target-info`
106
- private defaultTarget ?: string ,
107
110
public defaultSDK ?: string ,
108
111
public customSDK ?: string ,
109
112
public xcTestPath ?: string ,
113
+ public swiftTestingPath ?: string ,
110
114
public swiftPMTestingHelperPath ?: string
111
- ) { }
115
+ ) {
116
+ this . swiftVersionString = targetInfo . compilerVersion ;
117
+ }
112
118
113
119
static async create ( ) : Promise < SwiftToolchain > {
114
120
const swiftFolderPath = await this . getSwiftFolderPath ( ) ;
@@ -125,22 +131,32 @@ export class SwiftToolchain {
125
131
runtimePath ,
126
132
customSDK ?? defaultSDK
127
133
) ;
134
+ const swiftTestingPath = await this . getSwiftTestingPath (
135
+ targetInfo ,
136
+ swiftVersion ,
137
+ runtimePath ,
138
+ customSDK ?? defaultSDK
139
+ ) ;
128
140
const swiftPMTestingHelperPath = await this . getSwiftPMTestingHelperPath ( toolchainPath ) ;
129
141
130
142
return new SwiftToolchain (
131
143
swiftFolderPath ,
132
144
toolchainPath ,
133
- targetInfo . compilerVersion ,
145
+ targetInfo ,
134
146
swiftVersion ,
135
147
runtimePath ,
136
- targetInfo . target ?. triple ,
137
148
defaultSDK ,
138
149
customSDK ,
139
150
xcTestPath ,
151
+ swiftTestingPath ,
140
152
swiftPMTestingHelperPath
141
153
) ;
142
154
}
143
155
156
+ public get unversionedTriple ( ) : string | undefined {
157
+ return this . targetInfo . target ?. unversionedTriple ;
158
+ }
159
+
144
160
/** build flags */
145
161
public get buildFlags ( ) : BuildFlags {
146
162
return new BuildFlags ( this ) ;
@@ -445,8 +461,8 @@ export class SwiftToolchain {
445
461
if ( this . runtimePath ) {
446
462
str += `\nRuntime Library Path: ${ this . runtimePath } ` ;
447
463
}
448
- if ( this . defaultTarget ) {
449
- str += `\nDefault Target: ${ this . defaultTarget } ` ;
464
+ if ( this . targetInfo . target ?. triple ) {
465
+ str += `\nDefault Target: ${ this . targetInfo . target ?. triple } ` ;
450
466
}
451
467
if ( this . defaultSDK ) {
452
468
str += `\nDefault SDK: ${ this . defaultSDK } ` ;
@@ -638,6 +654,31 @@ export class SwiftToolchain {
638
654
return undefined ;
639
655
}
640
656
657
+ /**
658
+ * @param targetInfo swift target info
659
+ * @param swiftVersion parsed swift version
660
+ * @param runtimePath path to Swift runtime
661
+ * @param sdkroot path to swift SDK
662
+ * @returns path to folder where xctest can be found
663
+ */
664
+ private static async getSwiftTestingPath (
665
+ targetInfo : SwiftTargetInfo ,
666
+ swiftVersion : Version ,
667
+ runtimePath : string | undefined ,
668
+ sdkroot : string | undefined
669
+ ) : Promise < string | undefined > {
670
+ if ( process . platform !== "win32" ) {
671
+ return undefined ;
672
+ }
673
+ return this . getWindowsPlatformDLLPath (
674
+ "Testing" ,
675
+ targetInfo ,
676
+ swiftVersion ,
677
+ runtimePath ,
678
+ sdkroot
679
+ ) ;
680
+ }
681
+
641
682
/**
642
683
* @param targetInfo swift target info
643
684
* @param swiftVersion parsed swift version
@@ -663,80 +704,95 @@ export class SwiftToolchain {
663
704
return path . join ( developerDir , "usr" , "bin" ) ;
664
705
}
665
706
case "win32" : {
666
- // look up runtime library directory for XCTest alternatively
667
- const fallbackPath =
668
- runtimePath !== undefined &&
669
- ( await pathExists ( path . join ( runtimePath , "XCTest.dll" ) ) )
670
- ? runtimePath
671
- : undefined ;
672
- if ( ! sdkroot ) {
673
- return fallbackPath ;
674
- }
675
- const platformPath = path . dirname ( path . dirname ( path . dirname ( sdkroot ) ) ) ;
676
- const platformManifest = path . join ( platformPath , "Info.plist" ) ;
677
- if ( ( await pathExists ( platformManifest ) ) !== true ) {
678
- if ( fallbackPath ) {
679
- return fallbackPath ;
680
- }
681
- vscode . window . showWarningMessage (
682
- "XCTest not found due to non-standardized library layout. Tests explorer won't work as expected."
683
- ) ;
684
- return undefined ;
685
- }
686
- const data = await fs . readFile ( platformManifest , "utf8" ) ;
687
- let infoPlist ;
688
- try {
689
- infoPlist = plist . parse ( data ) as unknown as InfoPlist ;
690
- } catch ( error ) {
691
- vscode . window . showWarningMessage (
692
- `Unable to parse ${ platformManifest } : ${ error } `
693
- ) ;
694
- return undefined ;
695
- }
696
- const version = infoPlist . DefaultProperties . XCTEST_VERSION ;
697
- if ( ! version ) {
698
- throw Error ( "Info.plist is missing the XCTEST_VERSION key." ) ;
699
- }
700
-
701
- if ( swiftVersion . isGreaterThanOrEqual ( new Version ( 5 , 7 , 0 ) ) ) {
702
- let bindir : string ;
703
- const arch = targetInfo . target ?. triple . split ( "-" , 1 ) [ 0 ] ;
704
- switch ( arch ) {
705
- case "x86_64" :
706
- bindir = "bin64" ;
707
- break ;
708
- case "i686" :
709
- bindir = "bin32" ;
710
- break ;
711
- case "aarch64" :
712
- bindir = "bin64a" ;
713
- break ;
714
- default :
715
- throw Error ( `unsupported architecture ${ arch } ` ) ;
716
- }
717
- return path . join (
718
- platformPath ,
719
- "Developer" ,
720
- "Library" ,
721
- `XCTest-${ version } ` ,
722
- "usr" ,
723
- bindir
724
- ) ;
725
- } else {
726
- return path . join (
727
- platformPath ,
728
- "Developer" ,
729
- "Library" ,
730
- `XCTest-${ version } ` ,
731
- "usr" ,
732
- "bin"
733
- ) ;
734
- }
707
+ return await this . getWindowsPlatformDLLPath (
708
+ "XCTest" ,
709
+ targetInfo ,
710
+ swiftVersion ,
711
+ runtimePath ,
712
+ sdkroot
713
+ ) ;
735
714
}
736
715
}
737
716
return undefined ;
738
717
}
739
718
719
+ private static async getWindowsPlatformDLLPath (
720
+ type : "XCTest" | "Testing" ,
721
+ targetInfo : SwiftTargetInfo ,
722
+ swiftVersion : Version ,
723
+ runtimePath : string | undefined ,
724
+ sdkroot : string | undefined
725
+ ) : Promise < string | undefined > {
726
+ // look up runtime library directory for XCTest/Testing alternatively
727
+ const fallbackPath =
728
+ runtimePath !== undefined && ( await pathExists ( path . join ( runtimePath , `${ type } .dll` ) ) )
729
+ ? runtimePath
730
+ : undefined ;
731
+ if ( ! sdkroot ) {
732
+ return fallbackPath ;
733
+ }
734
+
735
+ const platformPath = path . dirname ( path . dirname ( path . dirname ( sdkroot ) ) ) ;
736
+ const platformManifest = path . join ( platformPath , "Info.plist" ) ;
737
+ if ( ( await pathExists ( platformManifest ) ) !== true ) {
738
+ if ( fallbackPath ) {
739
+ return fallbackPath ;
740
+ }
741
+ vscode . window . showWarningMessage (
742
+ `${ type } not found due to non-standardized library layout. Tests explorer won't work as expected.`
743
+ ) ;
744
+ return undefined ;
745
+ }
746
+ const data = await fs . readFile ( platformManifest , "utf8" ) ;
747
+ let infoPlist ;
748
+ try {
749
+ infoPlist = plist . parse ( data ) as unknown as InfoPlist ;
750
+ } catch ( error ) {
751
+ vscode . window . showWarningMessage ( `Unable to parse ${ platformManifest } : ${ error } ` ) ;
752
+ return undefined ;
753
+ }
754
+ const plistKey = type === "XCTest" ? "XCTEST_VERSION" : "SWIFT_TESTING_VERSION" ;
755
+ const version = infoPlist . DefaultProperties [ plistKey ] ;
756
+ if ( ! version ) {
757
+ throw Error ( `Info.plist is missing the ${ plistKey } key.` ) ;
758
+ }
759
+
760
+ if ( swiftVersion . isGreaterThanOrEqual ( new Version ( 5 , 7 , 0 ) ) ) {
761
+ let bindir : string ;
762
+ const arch = targetInfo . target ?. triple . split ( "-" , 1 ) [ 0 ] ;
763
+ switch ( arch ) {
764
+ case "x86_64" :
765
+ bindir = "bin64" ;
766
+ break ;
767
+ case "i686" :
768
+ bindir = "bin32" ;
769
+ break ;
770
+ case "aarch64" :
771
+ bindir = "bin64a" ;
772
+ break ;
773
+ default :
774
+ throw Error ( `unsupported architecture ${ arch } ` ) ;
775
+ }
776
+ return path . join (
777
+ platformPath ,
778
+ "Developer" ,
779
+ "Library" ,
780
+ `${ type } -${ version } ` ,
781
+ "usr" ,
782
+ bindir
783
+ ) ;
784
+ } else {
785
+ return path . join (
786
+ platformPath ,
787
+ "Developer" ,
788
+ "Library" ,
789
+ `${ type } -${ version } ` ,
790
+ "usr" ,
791
+ "bin"
792
+ ) ;
793
+ }
794
+ }
795
+
740
796
/** @returns swift target info */
741
797
private static async getSwiftTargetInfo ( ) : Promise < SwiftTargetInfo > {
742
798
try {
0 commit comments