Skip to content

Commit 3d7bb4b

Browse files
committed
Model swift commands
1 parent f70907c commit 3d7bb4b

File tree

3 files changed

+341
-37
lines changed

3 files changed

+341
-37
lines changed

Sources/SwiftlyCore/Commands.swift

+299
Original file line numberDiff line numberDiff line change
@@ -647,3 +647,302 @@ extension SystemCommand {
647647

648648
extension SystemCommand.TarCommand.CreateCommand: Runnable {}
649649
extension SystemCommand.TarCommand.ExtractCommand: Runnable {}
650+
651+
extension SystemCommand {
652+
public static func swift(executable: Executable = SwiftCommand.defaultExecutable) -> SwiftCommand {
653+
SwiftCommand(executable: executable)
654+
}
655+
656+
public struct SwiftCommand {
657+
public static var defaultExecutable: Executable { .name("swift") }
658+
659+
public var executable: Executable
660+
661+
public init(executable: Executable) {
662+
self.executable = executable
663+
}
664+
665+
func config() -> Configuration {
666+
var args: [String] = []
667+
668+
return Configuration(
669+
executable: self.executable,
670+
arguments: Arguments(args),
671+
environment: .inherit
672+
)
673+
}
674+
675+
public func package() -> PackageCommand {
676+
PackageCommand(self)
677+
}
678+
679+
public struct PackageCommand {
680+
var swift: SwiftCommand
681+
682+
init(_ swift: SwiftCommand) {
683+
self.swift = swift
684+
}
685+
686+
public func config() -> Configuration {
687+
var c = self.swift.config()
688+
689+
var args = c.arguments.storage.map(\.description)
690+
691+
args.append("package")
692+
693+
c.arguments = .init(args)
694+
695+
return c
696+
}
697+
698+
public func reset() -> ResetCommand {
699+
ResetCommand(self)
700+
}
701+
702+
public struct ResetCommand {
703+
var packageCommand: PackageCommand
704+
705+
init(_ packageCommand: PackageCommand) {
706+
self.packageCommand = packageCommand
707+
}
708+
709+
public func config() -> Configuration {
710+
var c = self.packageCommand.config()
711+
712+
var args = c.arguments.storage.map(\.description)
713+
714+
args.append("reset")
715+
716+
c.arguments = .init(args)
717+
718+
return c
719+
}
720+
}
721+
722+
public func clean() -> CleanCommand {
723+
CleanCommand(self)
724+
}
725+
726+
public struct CleanCommand {
727+
var packageCommand: PackageCommand
728+
729+
init(_ packageCommand: PackageCommand) {
730+
self.packageCommand = packageCommand
731+
}
732+
733+
public func config() -> Configuration {
734+
var c = self.packageCommand.config()
735+
736+
var args = c.arguments.storage.map(\.description)
737+
738+
args.append("clean")
739+
740+
c.arguments = .init(args)
741+
742+
return c
743+
}
744+
}
745+
746+
public func _init(_ options: InitCommand.Option...) -> InitCommand {
747+
self._init(options: options)
748+
}
749+
750+
public func _init(options: [InitCommand.Option]) -> InitCommand {
751+
InitCommand(self, options)
752+
}
753+
754+
public struct InitCommand {
755+
var packageCommand: PackageCommand
756+
757+
var options: [Option]
758+
759+
public enum Option {
760+
case type(String)
761+
case packagePath(FilePath)
762+
763+
func args() -> [String] {
764+
switch self {
765+
case let .type(type):
766+
return ["--type=\(type)"]
767+
case let .packagePath(packagePath):
768+
return ["--package-path=\(packagePath)"]
769+
}
770+
}
771+
}
772+
773+
init(_ packageCommand: PackageCommand, _ options: [Option]) {
774+
self.packageCommand = packageCommand
775+
self.options = options
776+
}
777+
778+
public func config() -> Configuration {
779+
var c = self.packageCommand.config()
780+
781+
var args = c.arguments.storage.map(\.description)
782+
783+
args.append("init")
784+
785+
for opt in self.options {
786+
args.append(contentsOf: opt.args())
787+
}
788+
789+
c.arguments = .init(args)
790+
791+
return c
792+
}
793+
}
794+
}
795+
796+
public func sdk() -> SdkCommand {
797+
SdkCommand(self)
798+
}
799+
800+
public struct SdkCommand {
801+
var swift: SwiftCommand
802+
803+
init(_ swift: SwiftCommand) {
804+
self.swift = swift
805+
}
806+
807+
public func config() -> Configuration {
808+
var c = self.swift.config()
809+
810+
var args = c.arguments.storage.map(\.description)
811+
812+
args.append("sdk")
813+
814+
c.arguments = .init(args)
815+
816+
return c
817+
}
818+
819+
public func install(_ bundlePathOrUrl: String, checksum: String? = nil) -> InstallCommand {
820+
InstallCommand(self, bundlePathOrUrl, checksum: checksum)
821+
}
822+
823+
public struct InstallCommand {
824+
var sdkCommand: SdkCommand
825+
var bundlePathOrUrl: String
826+
var checksum: String?
827+
828+
init(_ sdkCommand: SdkCommand, _ bundlePathOrUrl: String, checksum: String?) {
829+
self.sdkCommand = sdkCommand
830+
self.bundlePathOrUrl = bundlePathOrUrl
831+
self.checksum = checksum
832+
}
833+
834+
public func config() -> Configuration {
835+
var c = self.sdkCommand.config()
836+
837+
var args = c.arguments.storage.map(\.description)
838+
839+
args.append("install")
840+
841+
args.append(self.bundlePathOrUrl)
842+
843+
if let checksum = self.checksum {
844+
args.append("--checksum=\(checksum)")
845+
}
846+
847+
c.arguments = .init(args)
848+
849+
return c
850+
}
851+
}
852+
853+
public func remove(_ sdkIdOrBundleName: String) -> RemoveCommand {
854+
RemoveCommand(self, sdkIdOrBundleName)
855+
}
856+
857+
public struct RemoveCommand {
858+
var sdkCommand: SdkCommand
859+
var sdkIdOrBundleName: String
860+
861+
init(_ sdkCommand: SdkCommand, _ sdkIdOrBundleName: String) {
862+
self.sdkCommand = sdkCommand
863+
self.sdkIdOrBundleName = sdkIdOrBundleName
864+
}
865+
866+
public func config() -> Configuration {
867+
var c = self.sdkCommand.config()
868+
869+
var args = c.arguments.storage.map(\.description)
870+
871+
args.append("remove")
872+
873+
args.append(self.sdkIdOrBundleName)
874+
875+
c.arguments = .init(args)
876+
877+
return c
878+
}
879+
}
880+
}
881+
882+
public func build(_ options: BuildCommand.Option...) -> BuildCommand {
883+
BuildCommand(self, options)
884+
}
885+
886+
public struct BuildCommand {
887+
var swift: SwiftCommand
888+
var options: [Option]
889+
890+
init(_ swift: SwiftCommand, _ options: [Option]) {
891+
self.swift = swift
892+
self.options = options
893+
}
894+
895+
public func config() -> Configuration {
896+
var c = self.swift.config()
897+
898+
var args = c.arguments.storage.map(\.description)
899+
900+
args.append("build")
901+
902+
for opt in self.options {
903+
args.append(contentsOf: opt.args())
904+
}
905+
906+
c.arguments = .init(args)
907+
908+
return c
909+
}
910+
911+
public enum Option {
912+
case arch(String)
913+
case configuration(String)
914+
case packagePath(FilePath)
915+
case pkgConfigPath(String)
916+
case product(String)
917+
case swiftSdk(String)
918+
case staticSwiftStdlib
919+
920+
func args() -> [String] {
921+
switch self {
922+
case let .arch(arch):
923+
return ["--arch=\(arch)"]
924+
case let .configuration(configuration):
925+
return ["--configuration=\(configuration)"]
926+
case let .packagePath(packagePath):
927+
return ["--package-path=\(packagePath)"]
928+
case let .pkgConfigPath(pkgConfigPath):
929+
return ["--pkg-config-path=\(pkgConfigPath)"]
930+
case let .swiftSdk(sdk):
931+
return ["--swift-sdk=\(sdk)"]
932+
case .staticSwiftStdlib:
933+
return ["--static-swift-stdlib"]
934+
case let .product(product):
935+
return ["--product=\(product)"]
936+
}
937+
}
938+
}
939+
}
940+
}
941+
}
942+
943+
extension SystemCommand.SwiftCommand.PackageCommand.ResetCommand: Runnable {}
944+
extension SystemCommand.SwiftCommand.PackageCommand.CleanCommand: Runnable {}
945+
extension SystemCommand.SwiftCommand.PackageCommand.InitCommand: Runnable {}
946+
extension SystemCommand.SwiftCommand.SdkCommand.InstallCommand: Runnable {}
947+
extension SystemCommand.SwiftCommand.SdkCommand.RemoveCommand: Runnable {}
948+
extension SystemCommand.SwiftCommand.BuildCommand: Runnable {}

Tests/SwiftlyTests/CommandLineTests.swift

+33-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ public struct CommandLineTests {
134134
}
135135
)
136136
func testTar() async throws {
137-
// GIVEN a simple directory structure
138137
let tmp = fs.mktemp()
139138
try await fs.mkdir(atPath: tmp)
140139
let readme = "README.md"
@@ -162,4 +161,37 @@ public struct CommandLineTests {
162161
let contents2 = try await String(contentsOf: tmp3 / readme, encoding: .utf8)
163162
#expect(contents2 == "README")
164163
}
164+
165+
@Test func testSwiftModel() async throws {
166+
var config = sys.swift().package().reset().config()
167+
#expect(String(describing: config) == "swift package reset")
168+
169+
config = sys.swift().package().clean().config()
170+
#expect(String(describing: config) == "swift package clean")
171+
172+
config = sys.swift().sdk().install("path/to/bundle", checksum: "deadbeef").config()
173+
#expect(String(describing: config) == "swift sdk install path/to/bundle --checksum=deadbeef")
174+
175+
config = sys.swift().sdk().remove("some.bundle").config()
176+
#expect(String(describing: config) == "swift sdk remove some.bundle")
177+
178+
config = sys.swift().build(.arch("x86_64"), .configuration("release"), .pkgConfigPath("path/to/pc"), .swiftSdk("sdk.id"), .staticSwiftStdlib, .product("product1")).config()
179+
#expect(String(describing: config) == "swift build --arch=x86_64 --configuration=release --pkg-config-path=path/to/pc --swift-sdk=sdk.id --static-swift-stdlib --product=product1")
180+
181+
config = sys.swift().build().config()
182+
#expect(String(describing: config) == "swift build")
183+
}
184+
185+
@Test(
186+
.tags(.medium),
187+
.enabled {
188+
try await sys.SwiftCommand.defaultExecutable.exists()
189+
}
190+
)
191+
func testSwift() async throws {
192+
let tmp = fs.mktemp()
193+
try await fs.mkdir(atPath: tmp)
194+
try await sys.swift().package()._init(.packagePath(tmp), .type("executable")).run(Swiftly.currentPlatform)
195+
try await sys.swift().build(.packagePath(tmp), .configuration("release"))
196+
}
165197
}

0 commit comments

Comments
 (0)