diff --git a/CHANGELOG.md b/CHANGELOG.md index 39db45d26..8f01fe6a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ Please, check out guidelines: https://keepachangelog.com/en/1.0.0/ ## Next version +### Changed + +- Replace ReactiveTask with SwiftShell https://github.com/tuist/tuist/pull/179 by @pepibumur. + +### Fixed + +- Carthage up command not running when the `Cartfile.resolved` file doesn't exist https://github.com/tuist/tuist/pull/179 by @pepibumur. + ## 0.10.0 ### Fixed diff --git a/Package.resolved b/Package.resolved index 61a5b556c..84a69d4e6 100644 --- a/Package.resolved +++ b/Package.resolved @@ -10,60 +10,6 @@ "version": "4.3.0" } }, - { - "package": "core", - "repositoryURL": "https://github.com/tuist/core.git", - "state": { - "branch": null, - "revision": "4500863dd846244323b29cb0950cb861e1fddcd0", - "version": null - } - }, - { - "package": "Nimble", - "repositoryURL": "https://github.com/Quick/Nimble.git", - "state": { - "branch": null, - "revision": "7c61d8e7e830dd37f7161ce2b894be178532163c", - "version": "7.3.0" - } - }, - { - "package": "Quick", - "repositoryURL": "https://github.com/Quick/Quick.git", - "state": { - "branch": null, - "revision": "b060679e70d13c3c7dcd124201b5b1b34ce6f340", - "version": "1.3.1" - } - }, - { - "package": "ReactiveSwift", - "repositoryURL": "https://github.com/ReactiveCocoa/ReactiveSwift.git", - "state": { - "branch": null, - "revision": "4f6a12ae6762e825b0e19a4f7076eafa43847e6e", - "version": "4.0.0" - } - }, - { - "package": "ReactiveTask", - "repositoryURL": "https://github.com/Carthage/ReactiveTask.git", - "state": { - "branch": null, - "revision": "0f3be6022e2435e1bb91679bc2aabeff13eb794c", - "version": "0.15.0" - } - }, - { - "package": "Result", - "repositoryURL": "https://github.com/antitypical/Result.git", - "state": { - "branch": null, - "revision": "8fc088dcf72802801efeecba76ea8fb041fb773d", - "version": "4.0.0" - } - }, { "package": "SwiftPM", "repositoryURL": "https://github.com/apple/swift-package-manager", @@ -73,6 +19,15 @@ "version": "0.2.1" } }, + { + "package": "SwiftShell", + "repositoryURL": "https://github.com/kareman/SwiftShell", + "state": { + "branch": null, + "revision": "beebe43c986d89ea5359ac3adcb42dac94e5e08a", + "version": "4.1.2" + } + }, { "package": "xcodeproj", "repositoryURL": "https://github.com/tuist/xcodeproj.git", diff --git a/Package.swift b/Package.swift index bf37ce837..66c61ced4 100644 --- a/Package.swift +++ b/Package.swift @@ -14,8 +14,8 @@ let package = Package( dependencies: [ .package(url: "https://github.com/tuist/xcodeproj.git", .upToNextMinor(from: "6.0.0")), .package(url: "https://github.com/apple/swift-package-manager", .upToNextMinor(from: "0.2.1")), - .package(url: "https://github.com/Carthage/ReactiveTask.git", .upToNextMinor(from: "0.15.0")), .package(url: "https://github.com/jpsim/Yams.git", .upToNextMinor(from: "1.0.1")), + .package(url: "https://github.com/kareman/SwiftShell", from: "4.1.2"), ], targets: [ .target( @@ -52,7 +52,7 @@ let package = Package( ), .target( name: "TuistCore", - dependencies: ["Utility", "ReactiveTask"] + dependencies: ["Utility", "SwiftShell"] ), .target( name: "TuistCoreTesting", diff --git a/Sources/TuistCore/Utils/System.swift b/Sources/TuistCore/Utils/System.swift index 7797bb4a3..aef6cf076 100644 --- a/Sources/TuistCore/Utils/System.swift +++ b/Sources/TuistCore/Utils/System.swift @@ -1,7 +1,6 @@ import Basic import Foundation -import ReactiveSwift -import ReactiveTask +import SwiftShell public protocol Systeming { /// Runs a command in the shell and returns the result (exit status, standard output and standard error). @@ -50,17 +49,6 @@ public protocol Systeming { /// - Throws: An error if the command fails. func popen(_ launchPath: String, arguments: [String], verbose: Bool, workingDirectoryPath: AbsolutePath?, environment: [String: String]?) throws - /// Instantiates a SignalProducer that launches the given path. - /// - /// - Parameters: - /// - launchPath: Path to the binary or script to run. - /// - arguments: Arguments to be passed. - /// - print: When true, it outputs the output from the execution. - /// - workingDirectoryPath: The working directory path the task is executed from. - /// - environment: Environment that should be used when running the task. - /// - Returns: SignalProducer that encapsulates the task action. - func task(_ launchPath: String, arguments: [String], print: Bool, workingDirectoryPath: AbsolutePath?, environment: [String: String]?) -> SignalProducer - /// Returns the Swift version. /// /// - Returns: Swift version. @@ -77,7 +65,7 @@ public protocol Systeming { public struct SystemError: FatalError, Equatable { let stderror: String? - let exitcode: Int32 + let exitcode: Int public var type: ErrorType { return .abort @@ -87,7 +75,7 @@ public struct SystemError: FatalError, Equatable { return stderror ?? "Error running command" } - public init(stderror: String? = nil, exitcode: Int32) { + public init(stderror: String? = nil, exitcode: Int) { self.stderror = stderror self.exitcode = exitcode } @@ -101,10 +89,10 @@ public struct SystemError: FatalError, Equatable { public struct SystemResult { public let stdout: String public let stderror: String - public let exitcode: Int32 + public let exitcode: Int public var succeeded: Bool { return exitcode == 0 } - public init(stdout: String, stderror: String, exitcode: Int32) { + public init(stdout: String, stderror: String, exitcode: Int) { self.stdout = stdout self.stderror = stderror self.exitcode = exitcode @@ -184,12 +172,9 @@ public final class System: Systeming { if verbose { printCommand(launchPath, arguments: arguments) } - let task = self.task(launchPath, arguments: arguments, print: false, workingDirectoryPath: workingDirectoryPath, environment: environment) - if let output = task.single() { - return try output.dematerialize() - } else { - throw SystemError(stderror: "Error running command: \(commandString(launchPath, arguments: arguments))", exitcode: 1) - } + let context = self.context(workingDirectoryPath: workingDirectoryPath, environment: environment) + let result = context.run(launchPath, arguments, combineOutput: false) + return SystemResult(stdout: result.stdout, stderror: result.stderror, exitcode: result.exitcode) } /// Runs a command in the shell printing its output. @@ -230,56 +215,26 @@ public final class System: Systeming { if verbose { printCommand(launchPath, arguments: arguments) } - _ = task(launchPath, - arguments: arguments, - print: true, - workingDirectoryPath: workingDirectoryPath, - environment: environment).wait() + let context = self.context(workingDirectoryPath: workingDirectoryPath, environment: environment) + try context.runAndPrint(launchPath, arguments) } - /// Instantiates a SignalProducer that launches the given path. + /// Creates the context to run the command /// /// - Parameters: - /// - launchPath: Path to the binary or script to run. - /// - arguments: Arguments to be passed. - /// - print: When true, it outputs the output from the execution. /// - workingDirectoryPath: The working directory path the task is executed from. /// - environment: Environment that should be used when running the task. - /// - Returns: SignalProducer that encapsulates the task action. - public func task(_ launchPath: String, - arguments: [String], - print: Bool = false, - workingDirectoryPath: AbsolutePath? = nil, - environment: [String: String]? = nil) -> SignalProducer { - let task = Task(launchPath, - arguments: arguments, - workingDirectoryPath: workingDirectoryPath?.asString, - environment: environment) - return task.launch() - .on(value: { - if !print { return } - switch $0 { - case let .standardError(error): - FileHandle.standardError.write(error) - case let .standardOutput(output): - FileHandle.standardOutput.write(output) - default: - break - } - }) - .ignoreTaskData() - .mapError { (error: TaskError) -> SystemError in - switch error { - case let TaskError.posixError(code): - return SystemError(stderror: nil, exitcode: code) - case let TaskError.shellTaskFailed(_, code, standardError): - return SystemError(stderror: standardError, exitcode: code) - } - } - .map { data in - let stdout = String(data: data, encoding: .utf8)!.replacingOccurrences(of: "\n", with: "").chomp() - return SystemResult(stdout: stdout, stderror: "", exitcode: 0) - } + /// - Returns: The context to run the command on. + public func context(workingDirectoryPath: AbsolutePath?, + environment: [String: String]?) -> CustomContext { + var context = CustomContext(main) + if let workingDirectoryPath = workingDirectoryPath { + context.currentdirectory = workingDirectoryPath.asString + } + if let environment = environment { + context.env = environment + } + return context } /// Returns the Swift version. diff --git a/Sources/TuistCoreTesting/Utils/MockSystem.swift b/Sources/TuistCoreTesting/Utils/MockSystem.swift index d164c50a6..3ecda1009 100644 --- a/Sources/TuistCoreTesting/Utils/MockSystem.swift +++ b/Sources/TuistCoreTesting/Utils/MockSystem.swift @@ -1,18 +1,16 @@ import struct Basic.AbsolutePath import Foundation -import ReactiveSwift -import Result import TuistCore public final class MockSystem: Systeming { - private var stubs: [String: (stderror: String?, stdout: String?, exitstatus: Int32?)] = [:] + private var stubs: [String: (stderror: String?, stdout: String?, exitstatus: Int?)] = [:] private var calls: [String] = [] var swiftVersionStub: (() throws -> String?)? var whichStub: ((String) throws -> String?)? public init() {} - public func stub(args: [String], stderror: String? = nil, stdout: String? = nil, exitstatus: Int32? = nil) { + public func stub(args: [String], stderror: String? = nil, stdout: String? = nil, exitstatus: Int? = nil) { stubs[args.joined(separator: " ")] = (stderror: stderror, stdout: stdout, exitstatus: exitstatus) } @@ -50,24 +48,6 @@ public final class MockSystem: Systeming { } } - public func task(_ launchPath: String, arguments: [String], print _: Bool, workingDirectoryPath: AbsolutePath?, environment _: [String: String]?) -> SignalProducer { - var arguments = arguments - arguments.insert(launchPath, at: 0) - let command = arguments.joined(separator: " ") - calls.append(command) - return SignalProducer { () -> Result in - if let stub = self.stubs[command] { - if stub.exitstatus != 0 { - return Result.failure(SystemError(stderror: stub.stderror ?? "", exitcode: stub.exitstatus ?? -1)) - } else { - return Result.success(SystemResult(stdout: stub.stdout ?? "", stderror: "", exitcode: 0)) - } - } else { - return Result.failure(SystemError(stderror: "Command not supported: \(command)", exitcode: -1)) - } - } - } - public func swiftVersion() throws -> String? { return try swiftVersionStub?() } diff --git a/Sources/TuistKit/Graph/GraphUp.swift b/Sources/TuistKit/Graph/GraphUp.swift index dbcf40765..391978536 100644 --- a/Sources/TuistKit/Graph/GraphUp.swift +++ b/Sources/TuistKit/Graph/GraphUp.swift @@ -53,7 +53,6 @@ final class GraphUp: GraphUpping { printer.print(subsection: "Configuring \(command.name)") try command.meet(system: system, printer: printer, projectPath: project.path) } - printer.print(subsection: "Environment configured") } } } diff --git a/Sources/TuistKit/Models/UpCarthage.swift b/Sources/TuistKit/Models/UpCarthage.swift index ae0cc0550..9bac70139 100644 --- a/Sources/TuistKit/Models/UpCarthage.swift +++ b/Sources/TuistKit/Models/UpCarthage.swift @@ -54,7 +54,8 @@ class UpCarthage: Up, GraphInitiatable { /// - Throws: An error if the check fails. override func isMet(system: Systeming, projectPath: AbsolutePath) throws -> Bool { if try !upHomebrew.isMet(system: system, projectPath: projectPath) { return false } - return try carthage.outdated(path: projectPath).isEmpty + guard let outdated = try carthage.outdated(path: projectPath) else { return false } + return outdated.isEmpty } /// When the command is not met, this method runs it. @@ -71,7 +72,7 @@ class UpCarthage: Up, GraphInitiatable { } /// Updating Carthage dependencies. - let oudated = try carthage.outdated(path: projectPath) + let oudated = try carthage.outdated(path: projectPath) ?? [] try carthage.update(path: projectPath, platforms: platforms, dependencies: oudated) } diff --git a/Sources/TuistKit/Utils/Carthage.swift b/Sources/TuistKit/Utils/Carthage.swift index 1ff0d819b..cc2a5f327 100644 --- a/Sources/TuistKit/Utils/Carthage.swift +++ b/Sources/TuistKit/Utils/Carthage.swift @@ -24,7 +24,7 @@ protocol Carthaging { /// /// - Parameter path: Project directory. /// - Returns: List of outdated dependencies. - func outdated(path: AbsolutePath) throws -> [String] + func outdated(path: AbsolutePath) throws -> [String]? } final class Carthage: Carthaging { @@ -74,14 +74,14 @@ final class Carthage: Carthaging { /// /// - Parameter path: Project directory. /// - Returns: List of outdated dependencies. - func outdated(path: AbsolutePath) throws -> [String] { - var outdated: [String] = [] + func outdated(path: AbsolutePath) throws -> [String]? { let cartfileResolvedPath = path.appending(component: "Cartfile.resolved") if !fileHandler.exists(cartfileResolvedPath) { - return outdated + return nil } + var outdated: [String] = [] let carfileResolved = try fileHandler.readTextFile(cartfileResolvedPath) let carfileResolvedNSString = carfileResolved as NSString let jsonDecoder = JSONDecoder() diff --git a/Tests/TuistKitTests/Embed/EmbeddableTests.swift b/Tests/TuistKitTests/Embed/EmbeddableTests.swift index 998878902..f5927c2ef 100644 --- a/Tests/TuistKitTests/Embed/EmbeddableTests.swift +++ b/Tests/TuistKitTests/Embed/EmbeddableTests.swift @@ -100,7 +100,8 @@ final class EmbeddableTests: XCTestCase { func test_uuids_whenFramework() throws { try withUniversalFramework { - let expected: Set = Set(arrayLiteral: UUID(uuidString: "510FD121-B669-3524-A748-2DDF357A051C")!) + let expected: Set = Set(arrayLiteral: UUID(uuidString: "FB17107A-86FA-3880-92AC-C9AA9E04BA98")!, + UUID(uuidString: "510FD121-B669-3524-A748-2DDF357A051C")!) try XCTAssertEqual($0.uuids(), expected) } } diff --git a/Tests/TuistKitTests/Graph/GraphUpTests.swift b/Tests/TuistKitTests/Graph/GraphUpTests.swift index 8c114cf0c..f1c7a006b 100644 --- a/Tests/TuistKitTests/Graph/GraphUpTests.swift +++ b/Tests/TuistKitTests/Graph/GraphUpTests.swift @@ -35,7 +35,6 @@ final class GraphUpTests: XCTestCase { XCTAssertStandardOutput(printer, pattern: """ Setting up environment for project at /test Configuring GraphUpTests - Environment configured """) XCTAssertEqual(up.meetCallCount, 1) } @@ -47,7 +46,6 @@ final class GraphUpTests: XCTestCase { XCTAssertStandardOutput(printer, pattern: """ Setting up environment for project at /test - Environment configured """) XCTAssertEqual(up.meetCallCount, 0) } diff --git a/Tests/TuistKitTests/Models/UpCarthageTests.swift b/Tests/TuistKitTests/Models/UpCarthageTests.swift index f5f23e2fb..4ef4fe00e 100644 --- a/Tests/TuistKitTests/Models/UpCarthageTests.swift +++ b/Tests/TuistKitTests/Models/UpCarthageTests.swift @@ -43,6 +43,13 @@ final class UpCarthageTests: XCTestCase { XCTAssertFalse(try subject.isMet(system: system, projectPath: fileHandler.currentPath)) } + func test_isMet_when_carthage_doesnt_have_outdated_dependencies() throws { + upHomebrew.isMetStub = { _, _ in true } + carthage.outdatedStub = { _ in nil } + + XCTAssertFalse(try subject.isMet(system: system, projectPath: fileHandler.currentPath)) + } + func test_isMet_when_carthage_has_outdated_dependencies() throws { upHomebrew.isMetStub = { _, _ in true } carthage.outdatedStub = { _ in ["Dependency"] } diff --git a/Tests/TuistKitTests/Utils/Mocks/MockCarthage.swift b/Tests/TuistKitTests/Utils/Mocks/MockCarthage.swift index b11263bda..4726f3325 100644 --- a/Tests/TuistKitTests/Utils/Mocks/MockCarthage.swift +++ b/Tests/TuistKitTests/Utils/Mocks/MockCarthage.swift @@ -4,14 +4,14 @@ import Foundation @testable import TuistKit final class MockCarthage: Carthaging { - var outdatedStub: ((AbsolutePath) throws -> [String])? + var outdatedStub: ((AbsolutePath) throws -> [String]?)? var outdatedCallCount: UInt = 0 var updateStub: ((AbsolutePath, [Platform], [String]) throws -> Void)? var updateCallCount: UInt = 0 - func outdated(path: AbsolutePath) throws -> [String] { + func outdated(path: AbsolutePath) throws -> [String]? { outdatedCallCount += 1 - return try outdatedStub?(path) ?? [] + return try outdatedStub?(path) ?? nil } func update(path: AbsolutePath, platforms: [Platform], dependencies: [String]) throws {