Skip to content

Commit

Permalink
Merge pull request #87 from noppoMan/handle-signals
Browse files Browse the repository at this point in the history
Handle signals
  • Loading branch information
noppoMan authored Oct 18, 2017
2 parents d325cf1 + ea33c71 commit e6f02b9
Show file tree
Hide file tree
Showing 6 changed files with 212 additions and 1 deletion.
8 changes: 8 additions & 0 deletions Sources/Hexaville/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,14 @@ func detectVersion() -> String {
return "Unknown"
}

// SIGINT handling
SignalHandler.shared.trap(with: .int) {
defer {
exit(SignalHandler.Signal.int.rawValue)
}
SignalEventEmitter.shared.emit(with: .int)
}

let hexavilleCLI = CLI(name: "hexaville", version: detectVersion())
hexavilleCLI.commands = [GenerateProject(), Deploy(), RoutesCommand()]
_ = hexavilleCLI.go()
63 changes: 63 additions & 0 deletions Sources/HexavilleCore/EventEmitter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// EventEmitter.swift
// HexavillePackageDescription
//
// Created by Yuki Takei on 2017/10/17.
//

import Foundation
import Prorsum

/**
Thread safety EventEmitter
*/
public class EventEmitter<T> {

private var mutex = Mutex()

public var onceListenersCount: Int {
return onceListeners.count
}

public var onListenersCount: Int {
return onListeners.count
}

private var onceListeners: [(T) -> Void] = []

private var onListeners: [(T) -> Void] = []

public init() {}

public func emit(with value: T) {
defer {
mutex.lock()
onceListeners.removeAll()
mutex.unlock()
}

for handle in onceListeners {
handle(value)
}

for handle in onListeners {
handle(value)
}
}

public func once(handler: @escaping (T) -> Void) {
defer {
mutex.unlock()
}
mutex.lock()
onceListeners.append(handler)
}

public func on(handler: @escaping (T) -> Void) {
defer {
mutex.unlock()
}
mutex.lock()
onListeners.append(handler)
}
}
10 changes: 10 additions & 0 deletions Sources/HexavilleCore/Proc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,25 @@ public struct Proc {

public let stderr: Any?

public let pid: Int32?

public init(_ exetutablePath: String, _ arguments: [String] = [], environment: [String: String] = ProcessInfo.processInfo.environment) {
let process = Process()
process.launchPath = exetutablePath
process.arguments = arguments
process.environment = environment
process.launch()

// handle SIGINT
SignalEventEmitter.shared.once { sig in
assert(sig == .int)
process.interrupt()
}

process.waitUntilExit()
terminationStatus = process.terminationStatus
stdout = process.standardOutput
stderr = process.standardError
pid = process.processIdentifier
}
}
75 changes: 75 additions & 0 deletions Sources/HexavilleCore/SignalHandler.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//
// SignalHandler.swift
// HexavillePackageDescription
//
// Created by Yuki Takei on 2017/10/17.
//
#if os(OSX)
import Darwin
#else
import Glibc
#endif

import Foundation
import Dispatch

public class SignalEventEmitter: EventEmitter<SignalHandler.Signal> {
public static let shared = SignalEventEmitter()
}

public class SignalHandler {

public enum Signal: Int32 {
case hup = 1
case int = 2
case quit = 3
case abrt = 6
case kill = 9
case alrm = 14
case term = 15
}

public static let shared = SignalHandler()

private var handlers: [() -> Void] = []

private init() {}

public func trap(with signal: Signal, handler: @escaping () -> Void) {
handlers.append(handler)

let action: @convention(c) (Int32) -> () = { sig in
for handle in SignalHandler.shared.handlers {
handle()
}
}

#if os(macOS)
var signalAction = sigaction(
__sigaction_u: unsafeBitCast(action, to: __sigaction_u.self),
sa_mask: 0,
sa_flags: 0
)

_ = withUnsafePointer(to: &signalAction) { actionPointer in
sigaction(signal.rawValue, actionPointer, nil)
}

#elseif os(Linux)
var sigAction = sigaction()
sigAction.__sigaction_handler = unsafeBitCast(
action,
to: sigaction.__Unnamed_union___sigaction_handler.self
)
_ = sigaction(signal.rawValue, &sigAction, nil)
#endif
}

public func raise(_ signal: Signal) {
#if os(macOS)
_ = Darwin.raise(signal.rawValue)
#elseif os(Linux)
_ = Glibc.raise(signal.rawValue)
#endif
}
}
54 changes: 54 additions & 0 deletions Tests/HexavilleTests/EventEmitterTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// EventEmitterTests.swift
// HexavillePackageDescription
//
// Created by Yuki Takei on 2017/10/17.
//

import Foundation

import XCTest
@testable import HexavilleCore

class EventEmitterTests: XCTestCase {

func testOn() {
let exp = expectation(description: "testOnce")

let evm = EventEmitter<Int>()

evm.on {
XCTAssertEqual($0 + 1, 2)
exp.fulfill()
}

evm.emit(with: 1)

waitForExpectations(timeout: 1, handler: nil)

XCTAssertEqual(evm.onListenersCount, 1)
}

func testOnce() {
let exp = expectation(description: "testOnce")

let evm = EventEmitter<Int>()

evm.once {
XCTAssertEqual($0 + 1, 2)
exp.fulfill()
}

evm.emit(with: 1)

waitForExpectations(timeout: 1, handler: nil)

XCTAssertEqual(evm.onceListenersCount, 0)
}

static var allTests = [
("testOn", testOn),
("testOnce", testOnce),
]
}

3 changes: 2 additions & 1 deletion Tests/LinuxMain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ import XCTest
XCTMain([
testCase(HexavilefileLoaderTest.allTests),
testCase(DotEnvParserTests.allTests),
testCase(SwiftVersionTests.allTests)
testCase(SwiftVersionTests.allTests),
testCase(EventEmitterTests.allTests)
])

0 comments on commit e6f02b9

Please sign in to comment.