fastlane 2.73.0 → 2.74.0.beta.20180106010004
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/deliver/lib/assets/summary.html.erb +2 -1
- data/fastlane/lib/fastlane.rb +0 -2
- data/fastlane/lib/fastlane/commands_generator.rb +5 -2
- data/fastlane/lib/fastlane/lane_manager.rb +0 -45
- data/fastlane/lib/fastlane/lane_manager_base.rb +4 -4
- data/fastlane/lib/fastlane/runner.rb +4 -0
- data/fastlane/lib/fastlane/server/{command.rb → action_command.rb} +16 -25
- data/fastlane/lib/fastlane/server/action_command_return.rb +14 -0
- data/fastlane/lib/fastlane/server/command_executor.rb +0 -2
- data/fastlane/lib/fastlane/server/command_parser.rb +20 -0
- data/fastlane/lib/fastlane/server/control_command.rb +23 -0
- data/fastlane/lib/fastlane/server/json_return_value_processor.rb +71 -0
- data/fastlane/lib/fastlane/server/socket_server.rb +111 -112
- data/fastlane/lib/fastlane/server/socket_server_action_command_executor.rb +4 -3
- data/fastlane/lib/fastlane/swift_lane_manager.rb +17 -6
- data/fastlane/lib/fastlane/version.rb +1 -1
- data/fastlane/swift/ControlCommand.swift +71 -0
- data/fastlane/swift/FastlaneSwiftRunner/FastlaneSwiftRunner.xcodeproj/project.pbxproj +8 -0
- data/fastlane/swift/LaneFileProtocol.swift +55 -27
- data/fastlane/swift/RubyCommand.swift +3 -6
- data/fastlane/swift/RubyCommandable.swift +38 -0
- data/fastlane/swift/Runner.swift +6 -3
- data/fastlane/swift/SocketClient.swift +43 -27
- data/fastlane/swift/SocketResponse.swift +7 -2
- data/fastlane/swift/main.swift +5 -3
- metadata +24 -24
- data/fastlane/lib/.DS_Store +0 -0
- data/fastlane/lib/assets/.DS_Store +0 -0
- data/fastlane/lib/fastlane/.DS_Store +0 -0
- data/fastlane/lib/fastlane/actions/.DS_Store +0 -0
- data/fastlane/lib/fastlane/actions/docs/.DS_Store +0 -0
- data/fastlane/lib/fastlane/setup/.DS_Store +0 -0
@@ -1,4 +1,5 @@
|
|
1
|
-
require 'fastlane/server/
|
1
|
+
require 'fastlane/server/action_command_return.rb'
|
2
|
+
require 'fastlane/server/command_parser.rb'
|
2
3
|
require 'fastlane/server/command_executor.rb'
|
3
4
|
|
4
5
|
module Fastlane
|
@@ -44,7 +45,7 @@ module Fastlane
|
|
44
45
|
parameter_map: parameter_map
|
45
46
|
)
|
46
47
|
|
47
|
-
command_return =
|
48
|
+
command_return = ActionCommandReturn.new(
|
48
49
|
return_value: action_return,
|
49
50
|
return_value_type: action_class_ref.return_type,
|
50
51
|
closure_argument_value: closure_argument_value
|
@@ -88,7 +89,7 @@ module Fastlane
|
|
88
89
|
action_return = Fastlane::FastFile.sh(command_param, log: log_param, error_callback: error_callback)
|
89
90
|
end
|
90
91
|
|
91
|
-
command_return =
|
92
|
+
command_return = ActionCommandReturn.new(
|
92
93
|
return_value: action_return,
|
93
94
|
return_value_type: action_return_type,
|
94
95
|
closure_argument_value: closure_argument_value
|
@@ -26,23 +26,34 @@ module Fastlane
|
|
26
26
|
socket_thread = self.start_socket_thread
|
27
27
|
sleep(0.250) while socket_thread[:ready].nil?
|
28
28
|
# wait on socket_thread to be in ready state, then start the runner thread
|
29
|
-
|
29
|
+
self.cruise_swift_lane_in_thread(lane, parameters)
|
30
30
|
|
31
|
-
runner_thread.join
|
32
31
|
socket_thread.join
|
33
32
|
rescue Exception => ex # rubocop:disable Lint/RescueException
|
33
|
+
e = ex
|
34
|
+
end
|
35
|
+
# If we have a thread exception, drop that in the exception
|
36
|
+
# won't ever have a situation where e is non-nil, and socket_thread[:exception] is also non-nil
|
37
|
+
e ||= socket_thread[:exception]
|
38
|
+
|
39
|
+
unless e.nil?
|
40
|
+
print_lane_context
|
41
|
+
|
34
42
|
# We also catch Exception, since the implemented action might send a SystemExit signal
|
35
43
|
# (or similar). We still want to catch that, since we want properly finish running fastlane
|
36
44
|
# Tested with `xcake`, which throws a `Xcake::Informative` object
|
45
|
+
UI.error e.to_s if e.kind_of?(StandardError) # we don't want to print things like 'system exit'
|
46
|
+
end
|
37
47
|
|
38
|
-
|
39
|
-
|
40
|
-
|
48
|
+
skip_message = false
|
49
|
+
exit_reason = socket_thread[:exit_reason]
|
50
|
+
if exit_reason == :cancelled && e.nil?
|
51
|
+
skip_message = true
|
41
52
|
end
|
42
53
|
|
43
54
|
duration = ((Time.now - started) / 60.0).round
|
44
55
|
|
45
|
-
finish_fastlane(nil, duration, e)
|
56
|
+
finish_fastlane(nil, duration, e, skip_message: skip_message)
|
46
57
|
end
|
47
58
|
|
48
59
|
def self.display_lanes
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Fastlane
|
2
|
-
VERSION = '2.
|
2
|
+
VERSION = '2.74.0.beta.20180106010004'.freeze
|
3
3
|
DESCRIPTION = "The easiest way to automate beta deployments and releases for your iOS and Android apps".freeze
|
4
4
|
MINIMUM_XCODE_RELEASE = "7.0".freeze
|
5
5
|
RUBOCOP_REQUIREMENT = '0.49.1'.freeze
|
@@ -0,0 +1,71 @@
|
|
1
|
+
//
|
2
|
+
// ClientShutdownCommand.swift
|
3
|
+
// FastlaneRunner
|
4
|
+
//
|
5
|
+
// Created by Joshua Liebowitz on 1/3/18.
|
6
|
+
// Copyright © 2018 Joshua Liebowitz. All rights reserved.
|
7
|
+
//
|
8
|
+
|
9
|
+
import Foundation
|
10
|
+
|
11
|
+
struct ControlCommand: RubyCommandable {
|
12
|
+
static let commandKey = "command"
|
13
|
+
var type: CommandType { return .control }
|
14
|
+
|
15
|
+
enum ShutdownCommandType {
|
16
|
+
static let userMessageKey: String = "userMessage"
|
17
|
+
|
18
|
+
enum CancelReason {
|
19
|
+
static let reasonKey: String = "reason"
|
20
|
+
case clientError
|
21
|
+
case serverError
|
22
|
+
|
23
|
+
var reasonText: String {
|
24
|
+
switch self {
|
25
|
+
case .clientError:
|
26
|
+
return "clientError"
|
27
|
+
case .serverError:
|
28
|
+
return "serverError"
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
case done
|
34
|
+
case cancel(cancelReason: CancelReason)
|
35
|
+
|
36
|
+
var token: String {
|
37
|
+
switch self {
|
38
|
+
case .done:
|
39
|
+
return "done"
|
40
|
+
case .cancel:
|
41
|
+
return "cancelFastlaneRun"
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
let message: String?
|
47
|
+
let shutdownCommandType: ShutdownCommandType
|
48
|
+
var commandJson: String {
|
49
|
+
var jsonDictionary: [String: Any] = [ControlCommand.commandKey : self.shutdownCommandType.token]
|
50
|
+
|
51
|
+
if let message = message {
|
52
|
+
jsonDictionary[ShutdownCommandType.userMessageKey] = message
|
53
|
+
}
|
54
|
+
if case .cancel(let reason) = shutdownCommandType {
|
55
|
+
jsonDictionary[ShutdownCommandType.CancelReason.reasonKey] = reason.reasonText
|
56
|
+
}
|
57
|
+
|
58
|
+
let jsonData = try! JSONSerialization.data(withJSONObject: jsonDictionary, options: [])
|
59
|
+
let jsonString = String(data: jsonData, encoding: .utf8)!
|
60
|
+
return jsonString
|
61
|
+
}
|
62
|
+
|
63
|
+
init(commandType: ShutdownCommandType, message: String? = nil) {
|
64
|
+
self.shutdownCommandType = commandType
|
65
|
+
self.message = message
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
// Please don't remove the lines below
|
70
|
+
// They are used to detect outdated files
|
71
|
+
// FastlaneRunnerAPIVersion [0.9.2]
|
@@ -32,7 +32,9 @@
|
|
32
32
|
D55B28C91F6C588300DC42C5 /* Snapshotfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55B28C21F6C588300DC42C5 /* Snapshotfile.swift */; };
|
33
33
|
D5A7C48F1F7C4DAF00A91DE6 /* Appfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A7C48D1F7C4DAF00A91DE6 /* Appfile.swift */; };
|
34
34
|
D5A7C4901F7C4DAF00A91DE6 /* Fastfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A7C48E1F7C4DAF00A91DE6 /* Fastfile.swift */; };
|
35
|
+
D5B8A5B31FFDC49E00536B24 /* ControlCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B8A5B21FFDC49D00536B24 /* ControlCommand.swift */; };
|
35
36
|
D5BAFD121F7DAAFC0030B324 /* ArgumentProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5BAFD111F7DAAFC0030B324 /* ArgumentProcessor.swift */; };
|
37
|
+
D5D1DE991FFEE8EA00502A00 /* RubyCommandable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5D1DE981FFEE8E900502A00 /* RubyCommandable.swift */; };
|
36
38
|
/* End PBXBuildFile section */
|
37
39
|
|
38
40
|
/* Begin PBXFileReference section */
|
@@ -62,7 +64,9 @@
|
|
62
64
|
D55B28C21F6C588300DC42C5 /* Snapshotfile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Snapshotfile.swift; path = ../Snapshotfile.swift; sourceTree = "<group>"; };
|
63
65
|
D5A7C48D1F7C4DAF00A91DE6 /* Appfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Appfile.swift; path = ../Appfile.swift; sourceTree = "<group>"; };
|
64
66
|
D5A7C48E1F7C4DAF00A91DE6 /* Fastfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Fastfile.swift; path = ../Fastfile.swift; sourceTree = "<group>"; };
|
67
|
+
D5B8A5B21FFDC49D00536B24 /* ControlCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ControlCommand.swift; path = ../ControlCommand.swift; sourceTree = "<group>"; };
|
65
68
|
D5BAFD111F7DAAFC0030B324 /* ArgumentProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ArgumentProcessor.swift; path = ../ArgumentProcessor.swift; sourceTree = "<group>"; };
|
69
|
+
D5D1DE981FFEE8E900502A00 /* RubyCommandable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RubyCommandable.swift; path = ../RubyCommandable.swift; sourceTree = "<group>"; };
|
66
70
|
/* End PBXFileReference section */
|
67
71
|
|
68
72
|
/* Begin PBXFrameworksBuildPhase section */
|
@@ -107,7 +111,9 @@
|
|
107
111
|
B3BA65B11F5A325E00B34850 /* Networking */ = {
|
108
112
|
isa = PBXGroup;
|
109
113
|
children = (
|
114
|
+
D5B8A5B21FFDC49D00536B24 /* ControlCommand.swift */,
|
110
115
|
B3BA65A01F5A269100B34850 /* RubyCommand.swift */,
|
116
|
+
D5D1DE981FFEE8E900502A00 /* RubyCommandable.swift */,
|
111
117
|
B3BA65A11F5A269100B34850 /* Runner.swift */,
|
112
118
|
B3BA65A21F5A269100B34850 /* SocketClient.swift */,
|
113
119
|
B3BA65A31F5A269100B34850 /* SocketClientDelegateProtocol.swift */,
|
@@ -225,6 +231,7 @@
|
|
225
231
|
buildActionMask = 2147483647;
|
226
232
|
files = (
|
227
233
|
B3BA65A91F5A269100B34850 /* RubyCommand.swift in Sources */,
|
234
|
+
D5D1DE991FFEE8EA00502A00 /* RubyCommandable.swift in Sources */,
|
228
235
|
D55B28C41F6C588300DC42C5 /* Gymfile.swift in Sources */,
|
229
236
|
B302067D1F5E3E9000DE6EBD /* MatchfileProtocol.swift in Sources */,
|
230
237
|
B3BA65AC1F5A269100B34850 /* SocketClientDelegateProtocol.swift in Sources */,
|
@@ -243,6 +250,7 @@
|
|
243
250
|
B30206811F5E3E9000DE6EBD /* DeliverfileProtocol.swift in Sources */,
|
244
251
|
B3BA65AA1F5A269100B34850 /* Runner.swift in Sources */,
|
245
252
|
B3BA65AF1F5A2D5C00B34850 /* RunnerArgument.swift in Sources */,
|
253
|
+
D5B8A5B31FFDC49E00536B24 /* ControlCommand.swift in Sources */,
|
246
254
|
B302067E1F5E3E9000DE6EBD /* PrecheckfileProtocol.swift in Sources */,
|
247
255
|
B3BA65AD1F5A269100B34850 /* SocketResponse.swift in Sources */,
|
248
256
|
B3BA65A81F5A269100B34850 /* main.swift in Sources */,
|
@@ -10,8 +10,8 @@ import Foundation
|
|
10
10
|
|
11
11
|
public protocol LaneFileProtocol: class {
|
12
12
|
var fastlaneVersion: String { get }
|
13
|
-
static func runLane(named: String, parameters: [String : String])
|
14
|
-
|
13
|
+
static func runLane(named: String, parameters: [String : String]) -> Bool
|
14
|
+
|
15
15
|
func recordLaneDescriptions()
|
16
16
|
func beforeAll()
|
17
17
|
func afterAll(currentLane: String)
|
@@ -29,38 +29,54 @@ public extension LaneFileProtocol {
|
|
29
29
|
@objcMembers
|
30
30
|
public class LaneFile: NSObject, LaneFileProtocol {
|
31
31
|
private(set) static var fastfileInstance: Fastfile?
|
32
|
-
|
32
|
+
|
33
33
|
// Called before any lane is executed.
|
34
34
|
private func setupAllTheThings() {
|
35
|
-
// Step 1, add lange descriptions
|
36
|
-
(self as! Fastfile).recordLaneDescriptions()
|
37
|
-
|
38
|
-
// Step 2, run beforeAll() function
|
39
35
|
LaneFile.fastfileInstance!.beforeAll()
|
40
36
|
}
|
41
|
-
|
42
|
-
|
43
|
-
|
37
|
+
|
38
|
+
private static func trimLaneFromName(laneName: String) -> String {
|
39
|
+
return String(laneName.prefix(laneName.count - 4))
|
40
|
+
}
|
41
|
+
|
42
|
+
private static func trimLaneWithOptionsFromName(laneName: String) -> String {
|
43
|
+
return String(laneName.prefix(laneName.count - 12))
|
44
|
+
}
|
45
|
+
|
46
|
+
private static var laneFunctionNames: [String] {
|
47
|
+
var lanes: [String] = []
|
44
48
|
var methodCount: UInt32 = 0
|
45
49
|
let methodList = class_copyMethodList(self, &methodCount)
|
46
50
|
for i in 0..<Int(methodCount) {
|
47
51
|
let selName = sel_getName(method_getName(methodList![i]))
|
48
52
|
let name = String(cString: selName)
|
53
|
+
let lowercasedName = name.lowercased()
|
54
|
+
if lowercasedName.hasSuffix("lane") || lowercasedName.hasSuffix("lanewithoptions:") {
|
55
|
+
lanes.append(name)
|
56
|
+
}
|
57
|
+
}
|
58
|
+
return lanes
|
59
|
+
}
|
60
|
+
|
61
|
+
public static var lanes: [String : String] {
|
62
|
+
var laneToMethodName: [String : String] = [:]
|
63
|
+
self.laneFunctionNames.forEach { name in
|
49
64
|
let lowercasedName = name.lowercased()
|
50
65
|
if lowercasedName.hasSuffix("lane") {
|
51
66
|
laneToMethodName[lowercasedName] = name
|
52
|
-
let lowercasedNameNoLane =
|
67
|
+
let lowercasedNameNoLane = trimLaneFromName(laneName: lowercasedName)
|
53
68
|
laneToMethodName[lowercasedNameNoLane] = name
|
54
69
|
} else if lowercasedName.hasSuffix("lanewithoptions:") {
|
55
|
-
let lowercasedNameNoOptions =
|
70
|
+
let lowercasedNameNoOptions = trimLaneWithOptionsFromName(laneName: lowercasedName)
|
56
71
|
laneToMethodName[lowercasedNameNoOptions] = name
|
57
|
-
let lowercasedNameNoLane =
|
72
|
+
let lowercasedNameNoLane = trimLaneFromName(laneName: lowercasedNameNoOptions)
|
58
73
|
laneToMethodName[lowercasedNameNoLane] = name
|
59
74
|
}
|
60
75
|
}
|
76
|
+
|
61
77
|
return laneToMethodName
|
62
78
|
}
|
63
|
-
|
79
|
+
|
64
80
|
public static func loadFastfile() {
|
65
81
|
if self.fastfileInstance == nil {
|
66
82
|
let fastfileType: AnyObject.Type = NSClassFromString(self.className())!
|
@@ -69,38 +85,50 @@ public class LaneFile: NSObject, LaneFileProtocol {
|
|
69
85
|
self.fastfileInstance = currentFastfileInstance
|
70
86
|
}
|
71
87
|
}
|
72
|
-
|
73
|
-
public static func runLane(named: String, parameters: [String : String]) {
|
88
|
+
|
89
|
+
public static func runLane(named: String, parameters: [String : String]) -> Bool {
|
74
90
|
log(message: "Running lane: \(named)")
|
75
91
|
self.loadFastfile()
|
76
|
-
|
92
|
+
|
77
93
|
guard let fastfileInstance: Fastfile = self.fastfileInstance else {
|
78
94
|
let message = "Unable to instantiate class named: \(self.className())"
|
79
95
|
log(message: message)
|
80
96
|
fatalError(message)
|
81
97
|
}
|
82
|
-
|
83
|
-
// call all methods that need to be called before we start calling lanes
|
84
|
-
fastfileInstance.setupAllTheThings()
|
85
|
-
|
98
|
+
|
86
99
|
let currentLanes = self.lanes
|
87
100
|
let lowerCasedLaneRequested = named.lowercased()
|
88
|
-
|
101
|
+
|
89
102
|
guard let laneMethod = currentLanes[lowerCasedLaneRequested] else {
|
90
|
-
let
|
103
|
+
let laneNames = self.laneFunctionNames.map { laneFuctionName in
|
104
|
+
if laneFuctionName.hasSuffix("lanewithoptions:") {
|
105
|
+
return trimLaneWithOptionsFromName(laneName: laneFuctionName)
|
106
|
+
} else {
|
107
|
+
return trimLaneFromName(laneName: laneFuctionName)
|
108
|
+
}
|
109
|
+
}.joined(separator: ", ")
|
110
|
+
|
111
|
+
let message = "[!] Could not find lane '\(named)'. Available lanes: \(laneNames)"
|
91
112
|
log(message: message)
|
92
|
-
|
113
|
+
|
114
|
+
let shutdownCommand = ControlCommand(commandType: .cancel(cancelReason: .clientError), message: message)
|
115
|
+
_ = runner.executeCommand(shutdownCommand)
|
116
|
+
return false
|
93
117
|
}
|
94
|
-
|
118
|
+
|
119
|
+
// call all methods that need to be called before we start calling lanes
|
120
|
+
fastfileInstance.setupAllTheThings()
|
121
|
+
|
95
122
|
// We need to catch all possible errors here and display a nice message
|
96
123
|
_ = fastfileInstance.perform(NSSelectorFromString(laneMethod), with: parameters)
|
97
|
-
|
124
|
+
|
98
125
|
// only call on success
|
99
126
|
fastfileInstance.afterAll(currentLane: named)
|
100
127
|
log(message: "Done running lane: \(named) 🚀")
|
128
|
+
return true
|
101
129
|
}
|
102
130
|
}
|
103
131
|
|
104
132
|
// Please don't remove the lines below
|
105
133
|
// They are used to detect outdated files
|
106
|
-
// FastlaneRunnerAPIVersion [0.9.
|
134
|
+
// FastlaneRunnerAPIVersion [0.9.2]
|
@@ -8,11 +8,9 @@
|
|
8
8
|
|
9
9
|
import Foundation
|
10
10
|
|
11
|
-
protocol RubyCommandable {
|
12
|
-
var json: String { get }
|
13
|
-
}
|
14
|
-
|
15
11
|
struct RubyCommand: RubyCommandable {
|
12
|
+
var type: CommandType { return .action }
|
13
|
+
|
16
14
|
struct Argument {
|
17
15
|
enum ArgType {
|
18
16
|
case stringClosure
|
@@ -41,7 +39,6 @@ struct RubyCommand: RubyCommandable {
|
|
41
39
|
|
42
40
|
var json: String {
|
43
41
|
get {
|
44
|
-
|
45
42
|
if let someValue = value {
|
46
43
|
let typeJson: String
|
47
44
|
if let type = type {
|
@@ -102,7 +99,7 @@ struct RubyCommand: RubyCommandable {
|
|
102
99
|
callbackClosure(callbackArg)
|
103
100
|
}
|
104
101
|
|
105
|
-
var
|
102
|
+
var commandJson: String {
|
106
103
|
let argsArrayJson = self.args
|
107
104
|
.map { $0.json }
|
108
105
|
.filter { $0 != "" }
|
@@ -0,0 +1,38 @@
|
|
1
|
+
//
|
2
|
+
// RubyCommandable.swift
|
3
|
+
// FastlaneRunner
|
4
|
+
//
|
5
|
+
// Created by Joshua Liebowitz on 1/4/18.
|
6
|
+
// Copyright © 2018 Joshua Liebowitz. All rights reserved.
|
7
|
+
//
|
8
|
+
|
9
|
+
import Foundation
|
10
|
+
|
11
|
+
enum CommandType {
|
12
|
+
case action
|
13
|
+
case control
|
14
|
+
|
15
|
+
var token: String {
|
16
|
+
switch self {
|
17
|
+
case .action:
|
18
|
+
return "action"
|
19
|
+
case .control:
|
20
|
+
return "control"
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
protocol RubyCommandable {
|
26
|
+
var type: CommandType { get }
|
27
|
+
var commandJson: String { get }
|
28
|
+
}
|
29
|
+
|
30
|
+
extension RubyCommandable {
|
31
|
+
var json: String {
|
32
|
+
return "{\"commandType\" : \"\(self.type.token)\", \"command\" : \(self.commandJson)}"
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
// Please don't remove the lines below
|
37
|
+
// They are used to detect outdated files
|
38
|
+
// FastlaneRunnerAPIVersion [0.9.2]
|
data/fastlane/swift/Runner.swift
CHANGED
@@ -27,7 +27,7 @@ class Runner {
|
|
27
27
|
fileprivate var returnValue: String? // lol, so safe
|
28
28
|
fileprivate var currentlyExecutingCommand: RubyCommandable? = nil
|
29
29
|
fileprivate var shouldLeaveDispatchGroupDuringDisconnect = false
|
30
|
-
|
30
|
+
|
31
31
|
func executeCommand(_ command: RubyCommandable) -> String {
|
32
32
|
self.dispatchGroup.enter()
|
33
33
|
currentlyExecutingCommand = command
|
@@ -115,7 +115,10 @@ extension Runner : SocketClientDelegateProtocol {
|
|
115
115
|
}
|
116
116
|
}
|
117
117
|
self.dispatchGroup.leave()
|
118
|
-
|
118
|
+
case .clientInitiatedCancelAcknowledged:
|
119
|
+
verbose(message: "server acknowledged a cancel request")
|
120
|
+
self.dispatchGroup.leave()
|
121
|
+
|
119
122
|
case .alreadyClosedSockets, .connectionFailure, .malformedRequest, .malformedResponse, .serverError:
|
120
123
|
log(message: "error encountered while executing command:\n\(serverResponse)")
|
121
124
|
self.dispatchGroup.leave()
|
@@ -187,4 +190,4 @@ func verbose(message: String) {
|
|
187
190
|
|
188
191
|
// Please don't remove the lines below
|
189
192
|
// They are used to detect outdated files
|
190
|
-
// FastlaneRunnerAPIVersion [0.9.
|
193
|
+
// FastlaneRunnerAPIVersion [0.9.2]
|
@@ -13,6 +13,7 @@ public enum SocketClientResponse: Error {
|
|
13
13
|
case malformedRequest
|
14
14
|
case malformedResponse
|
15
15
|
case serverError
|
16
|
+
case clientInitiatedCancelAcknowledged
|
16
17
|
case commandTimeout(seconds: Int)
|
17
18
|
case connectionFailure
|
18
19
|
case success(returnedObject: String?, closureArgumentValue: String?)
|
@@ -27,7 +28,8 @@ class SocketClient: NSObject {
|
|
27
28
|
|
28
29
|
static let connectTimeoutSeconds = 2
|
29
30
|
static let defaultCommandTimeoutSeconds = 3_600 // Hopefully 1 hr is enough ¯\_(ツ)_/¯
|
30
|
-
static let doneToken = "done"
|
31
|
+
static let doneToken = "done" // TODO: remove these
|
32
|
+
static let cancelToken = "cancelFastlaneRun"
|
31
33
|
|
32
34
|
fileprivate var inputStream: InputStream!
|
33
35
|
fileprivate var outputStream: OutputStream!
|
@@ -106,7 +108,7 @@ class SocketClient: NSObject {
|
|
106
108
|
}
|
107
109
|
|
108
110
|
public func sendComplete() {
|
109
|
-
sendAbort
|
111
|
+
closeSession(sendAbort: true)
|
110
112
|
}
|
111
113
|
|
112
114
|
private func testDispatchTimeoutResult(_ timeoutResult: DispatchTimeoutResult, failureMessage: String, timeToWait: DispatchTimeInterval) -> Bool {
|
@@ -130,42 +132,50 @@ class SocketClient: NSObject {
|
|
130
132
|
private func stopOutputSession() {
|
131
133
|
outputStream.close()
|
132
134
|
}
|
133
|
-
|
134
|
-
private func
|
135
|
-
guard !self.cleaningUpAfterDone else {
|
136
|
-
// This will happen after we abort if there are commands waiting to be executed
|
137
|
-
// Need to check state of SocketClient in command runner to make sure we can accept `send`
|
138
|
-
socketDelegate?.commandExecuted(serverResponse: .alreadyClosedSockets)
|
139
|
-
return
|
140
|
-
}
|
141
|
-
|
142
|
-
if string == SocketClient.doneToken {
|
143
|
-
self.cleaningUpAfterDone = true
|
144
|
-
}
|
145
|
-
|
146
|
-
self.dispatchGroup.enter()
|
135
|
+
|
136
|
+
private func sendThroughQueue(string: String) {
|
147
137
|
streamQueue.async {
|
148
138
|
let data = string.data(using: .utf8)!
|
149
139
|
_ = data.withUnsafeBytes { self.outputStream.write($0, maxLength: data.count) }
|
150
140
|
}
|
141
|
+
}
|
151
142
|
|
152
|
-
|
143
|
+
private func privateSend(string: String) {
|
144
|
+
self.dispatchGroup.enter()
|
145
|
+
sendThroughQueue(string: string)
|
153
146
|
|
147
|
+
let timeoutSeconds = self.cleaningUpAfterDone ? 1 : self.commandTimeoutSeconds
|
154
148
|
let timeToWait = DispatchTimeInterval.seconds(timeoutSeconds)
|
155
149
|
let commandTimeout = DispatchTime.now() + timeToWait
|
156
150
|
let timeoutResult = self.dispatchGroup.wait(timeout: commandTimeout)
|
157
151
|
|
158
152
|
_ = testDispatchTimeoutResult(timeoutResult, failureMessage: "Ruby process didn't return after: \(SocketClient.connectTimeoutSeconds) seconds", timeToWait: timeToWait)
|
159
153
|
}
|
160
|
-
|
161
|
-
func
|
154
|
+
|
155
|
+
private func send(string: String) {
|
156
|
+
guard !self.cleaningUpAfterDone else {
|
157
|
+
// This will happen after we abort if there are commands waiting to be executed
|
158
|
+
// Need to check state of SocketClient in command runner to make sure we can accept `send`
|
159
|
+
socketDelegate?.commandExecuted(serverResponse: .alreadyClosedSockets)
|
160
|
+
return
|
161
|
+
}
|
162
|
+
|
163
|
+
if string == SocketClient.doneToken {
|
164
|
+
self.cleaningUpAfterDone = true
|
165
|
+
}
|
166
|
+
|
167
|
+
privateSend(string: string)
|
168
|
+
}
|
169
|
+
|
170
|
+
func closeSession(sendAbort: Bool = true) {
|
162
171
|
self.socketStatus = .closed
|
163
|
-
|
172
|
+
|
164
173
|
stopInputSession()
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
174
|
+
|
175
|
+
if sendAbort {
|
176
|
+
send(rubyCommand: ControlCommand(commandType: .done))
|
177
|
+
}
|
178
|
+
|
169
179
|
stopOutputSession()
|
170
180
|
self.socketDelegate?.connectionsClosed()
|
171
181
|
}
|
@@ -188,7 +198,7 @@ extension SocketClient: StreamDelegate {
|
|
188
198
|
|
189
199
|
case Stream.Event.errorOccurred:
|
190
200
|
verbose(message: "input stream error occurred")
|
191
|
-
sendAbort
|
201
|
+
closeSession(sendAbort: true)
|
192
202
|
|
193
203
|
case Stream.Event.hasBytesAvailable:
|
194
204
|
read()
|
@@ -246,7 +256,8 @@ extension SocketClient: StreamDelegate {
|
|
246
256
|
|
247
257
|
func handleFailure(message: [String]) {
|
248
258
|
log(message: "Encountered a problem: \(message.joined(separator:"\n"))")
|
249
|
-
|
259
|
+
let shutdownCommand = ControlCommand(commandType: .cancel(cancelReason: .serverError))
|
260
|
+
self.send(rubyCommand: shutdownCommand)
|
250
261
|
}
|
251
262
|
|
252
263
|
func processResponse(string: String) {
|
@@ -261,6 +272,10 @@ extension SocketClient: StreamDelegate {
|
|
261
272
|
let socketResponse = SocketResponse(payload: responseString)
|
262
273
|
verbose(message: "response is: \(responseString)")
|
263
274
|
switch socketResponse.responseType {
|
275
|
+
case .clientInitiatedCancel:
|
276
|
+
self.socketDelegate?.commandExecuted(serverResponse: .clientInitiatedCancelAcknowledged)
|
277
|
+
self.closeSession(sendAbort: false)
|
278
|
+
|
264
279
|
case .failure(let failureInformation):
|
265
280
|
self.socketDelegate?.commandExecuted(serverResponse: .serverError)
|
266
281
|
self.handleFailure(message: failureInformation)
|
@@ -274,10 +289,11 @@ extension SocketClient: StreamDelegate {
|
|
274
289
|
// cool, ready for next command
|
275
290
|
break
|
276
291
|
}
|
292
|
+
|
277
293
|
self.dispatchGroup.leave() // should now pull the next piece of work
|
278
294
|
}
|
279
295
|
}
|
280
296
|
|
281
297
|
// Please don't remove the lines below
|
282
298
|
// They are used to detect outdated files
|
283
|
-
// FastlaneRunnerAPIVersion [0.9.
|
299
|
+
// FastlaneRunnerAPIVersion [0.9.2]
|