Remplace ReactiveTask with SwiftShell (#179)
* Remplace ReactiveTask with SwiftShell * Update CHANGELOG * Remove Result import * Fix issue with UpCarthage don't running when the Cartfile.resolved is missing * Update CHANGELOG
This commit is contained in:
parent
aa7c363bd2
commit
3571783ad2
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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<SystemResult, SystemError>
|
||||
|
||||
/// 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<SystemResult, SystemError> {
|
||||
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.
|
||||
|
|
|
@ -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<SystemResult, SystemError> {
|
||||
var arguments = arguments
|
||||
arguments.insert(launchPath, at: 0)
|
||||
let command = arguments.joined(separator: " ")
|
||||
calls.append(command)
|
||||
return SignalProducer { () -> Result<SystemResult, SystemError> 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?()
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -100,7 +100,8 @@ final class EmbeddableTests: XCTestCase {
|
|||
|
||||
func test_uuids_whenFramework() throws {
|
||||
try withUniversalFramework {
|
||||
let expected: Set<UUID> = Set(arrayLiteral: UUID(uuidString: "510FD121-B669-3524-A748-2DDF357A051C")!)
|
||||
let expected: Set<UUID> = Set(arrayLiteral: UUID(uuidString: "FB17107A-86FA-3880-92AC-C9AA9E04BA98")!,
|
||||
UUID(uuidString: "510FD121-B669-3524-A748-2DDF357A051C")!)
|
||||
try XCTAssertEqual($0.uuids(), expected)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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"] }
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue