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:
Pedro Piñera Buendía 2018-12-20 13:36:43 +01:00 committed by GitHub
parent aa7c363bd2
commit 3571783ad2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 62 additions and 158 deletions

View File

@ -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

View File

@ -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",

View File

@ -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",

View File

@ -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.

View File

@ -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?()
}

View File

@ -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")
}
}
}

View File

@ -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)
}

View File

@ -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()

View File

@ -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)
}
}

View File

@ -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)
}

View File

@ -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"] }

View File

@ -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 {