Introduced Swift Package Manager and XCTest instead of swift-tap
This commit is contained in:
parent
3c86124ed7
commit
50d04aad0c
|
@ -1,5 +1,7 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
|
.build/
|
||||||
build/
|
build/
|
||||||
y-build/
|
y-build/
|
||||||
|
|
||||||
|
*.xcodeproj/
|
||||||
|
|
|
@ -15,10 +15,3 @@ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPO
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
||||||
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
====================================================================================================
|
|
||||||
Includes swift-tap
|
|
||||||
https://github.com/dankogai/swift-tap
|
|
||||||
Copyright (c) 2016 Dan Kogai
|
|
||||||
Released under the MIT License.
|
|
||||||
- See "Sources/Test/TAP.swift"
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
// swift-tools-version:3.1
|
||||||
|
|
||||||
|
import PackageDescription
|
||||||
|
|
||||||
|
let package = Package(
|
||||||
|
name: "TimeSpecification",
|
||||||
|
swiftLanguageVersions:[3]
|
||||||
|
)
|
|
@ -30,7 +30,7 @@ public enum Clock {
|
||||||
Build and install:
|
Build and install:
|
||||||
`./build-install.rb --install-prefix=/path/to/your/system --install`
|
`./build-install.rb --install-prefix=/path/to/your/system --install`
|
||||||
Then, you can use it in your project:
|
Then, you can use it in your project:
|
||||||
`swiftc ./your/project/main.swift -I/path/to/your/system/include -L/path/to/your/system/lib`
|
`swiftc ./your/project/main.swift -I/path/to/your/system/include -L/path/to/your/system/lib -lSwiftTimeSpecification`
|
||||||
|
|
||||||
# Sample Code
|
# Sample Code
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,149 +0,0 @@
|
||||||
// https://github.com/dankogai/swift-tap/blob/master/tap/tap.swift
|
|
||||||
|
|
||||||
//
|
|
||||||
// tap.swift
|
|
||||||
// tap
|
|
||||||
//
|
|
||||||
// Created by Dan Kogai on 1/21/16.
|
|
||||||
// Copyright © 2016 Dan Kogai. All rights reserved.
|
|
||||||
//
|
|
||||||
/*
|
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2016 Dan Kogai
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if os(Linux)
|
|
||||||
import Glibc
|
|
||||||
#else
|
|
||||||
import Darwin
|
|
||||||
#endif
|
|
||||||
|
|
||||||
open class TAP {
|
|
||||||
var tests = 0, runs = [Bool]()
|
|
||||||
public init() {}
|
|
||||||
public init(tests:Int) {
|
|
||||||
self.plan(tests)
|
|
||||||
}
|
|
||||||
/// sets the number of tests to run. call it before the first test
|
|
||||||
open func plan(_ tests:Int) {
|
|
||||||
self.tests = tests
|
|
||||||
print("1..\(tests)")
|
|
||||||
}
|
|
||||||
/// ok if `predicate` is true
|
|
||||||
@discardableResult
|
|
||||||
open func ok(_ predicate:@autoclosure ()->Bool, _ message:String = "")->Bool {
|
|
||||||
let ok = predicate()
|
|
||||||
runs.append(ok)
|
|
||||||
let ornot = ok ? "" : "not "
|
|
||||||
print("\(ornot)ok \(runs.count) - \(message)")
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
/// ok if `actual` == `expected`
|
|
||||||
@discardableResult
|
|
||||||
open func eq<T:Equatable>(_ actual:T, _ expected:T, _ message:String = "")->Bool {
|
|
||||||
if ok(actual == expected, message) { return true }
|
|
||||||
print("# got: \(actual)")
|
|
||||||
print("# expected: \(expected)")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
/// ok if `actual` == `expected`
|
|
||||||
@discardableResult
|
|
||||||
open func eq<T:Equatable>(_ actual:T?, _ expected:T?, _ message:String = "")->Bool {
|
|
||||||
if ok(actual == expected, message) { return true }
|
|
||||||
print("# got: \(actual as T?)")
|
|
||||||
print("# expected: \(expected as T?)")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
/// ok if arrays are `actual` == `expected`
|
|
||||||
@discardableResult
|
|
||||||
open func eq<T:Equatable>(_ actual:[T], _ expected:[T], _ message:String = "")->Bool {
|
|
||||||
if ok(actual == expected, message) { return true }
|
|
||||||
print("# got: \(actual)")
|
|
||||||
print("# expected: \(expected)")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
/// ok if dictionaries are `actual` == `expected`
|
|
||||||
@discardableResult
|
|
||||||
open func eq<K:Hashable,V:Equatable>(_ actual:[K:V], _ expected:[K:V], _ message:String = "")->Bool {
|
|
||||||
if ok(actual == expected, message) { return true }
|
|
||||||
print("# got: \(actual)")
|
|
||||||
print("# expected: \(expected)")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
@discardableResult
|
|
||||||
/// ok if `actual` != `expected`
|
|
||||||
open func ne<T:Equatable>(_ actual:T, _ expected:T, _ message:String = "")->Bool {
|
|
||||||
if ok(actual != expected, message) { return true }
|
|
||||||
print("# got: \(actual)")
|
|
||||||
print("# expected: anthing but \(expected)")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
/// ok if `actual` != `expected`
|
|
||||||
@discardableResult
|
|
||||||
open func ne<T:Equatable>(_ actual:T?, _ expected:T?, _ message:String = "")->Bool {
|
|
||||||
if ok(actual != expected, message) { return true }
|
|
||||||
print("# got: \(actual as T?)")
|
|
||||||
print("# expected: anthing but \(expected as T?)")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
/// ok if arrays are `actual` == `expected`
|
|
||||||
@discardableResult
|
|
||||||
open func ne<T:Equatable>(_ actual:[T], _ expected:[T], _ message:String = "")->Bool {
|
|
||||||
if ok(actual != expected, message) { return true }
|
|
||||||
print("# got: \(actual)")
|
|
||||||
print("# expected: anthing but \(expected)")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
/// ok if dictionaries are `actual` == `expected`
|
|
||||||
@discardableResult
|
|
||||||
open func ne<K:Hashable,V:Equatable>(_ actual:[K:V], _ expected:[K:V], _ message:String = "")->Bool {
|
|
||||||
if ok(actual != expected, message) { return true }
|
|
||||||
print("# got: \(actual)")
|
|
||||||
print("# expected: anthing but \(expected)")
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
/// checks the test results, print stuff if neccesary,
|
|
||||||
/// and `exit()` with code == number of failures
|
|
||||||
@discardableResult
|
|
||||||
open func done(dontExit nx:Bool = false)->[Bool] {
|
|
||||||
if runs.count == 0 && nx != true {
|
|
||||||
print("# no test run!")
|
|
||||||
exit(-1)
|
|
||||||
}
|
|
||||||
if tests == 0 {
|
|
||||||
print("1..\(runs.count)")
|
|
||||||
}
|
|
||||||
else if runs.count != tests {
|
|
||||||
print("not ok \(runs.count + 1) - planned to run \(tests) but actually ran \(runs.count)")
|
|
||||||
runs.append(false)
|
|
||||||
if nx != true { exit(-1) }
|
|
||||||
}
|
|
||||||
if nx != true {
|
|
||||||
let code = min(254, runs.filter{ $0 == false }.count)
|
|
||||||
exit(Int32(code))
|
|
||||||
}
|
|
||||||
return runs
|
|
||||||
}
|
|
||||||
deinit {
|
|
||||||
done(dontExit:true)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
/***************************************************************************************************
|
|
||||||
test.swift
|
|
||||||
© 2016 YOCKOW.
|
|
||||||
Licensed under MIT License.
|
|
||||||
See "LICENSE.txt" for more information.
|
|
||||||
**************************************************************************************************/
|
|
||||||
|
|
||||||
// FIXME: These are irresponsible tests below.
|
|
||||||
|
|
||||||
#if os(Linux)
|
|
||||||
import Glibc
|
|
||||||
#elseif os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
|
|
||||||
import Darwin
|
|
||||||
#else
|
|
||||||
// UNKNOWN OS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
import TimeSpecification
|
|
||||||
|
|
||||||
let test = TAP()
|
|
||||||
|
|
||||||
// Normalization Tests
|
|
||||||
let N1 = TimeSpecification(seconds:0, nanoseconds:1_234_567_890)
|
|
||||||
let N2 = TimeSpecification(seconds:-1, nanoseconds:-1_234_567_890)
|
|
||||||
test.ok(N1.seconds == 1 && N1.nanoseconds == 234_567_890, "Normalization Test 1")
|
|
||||||
test.ok(N2.seconds == -3 && N2.nanoseconds == 765_432_110, "Normalization Test 2")
|
|
||||||
|
|
||||||
// Comparison Tests
|
|
||||||
let C1 = TimeSpecification(seconds:100, nanoseconds:100)
|
|
||||||
let C2 = TimeSpecification(seconds: 98, nanoseconds:2_000_000_100)
|
|
||||||
let C3 = TimeSpecification(seconds:200, nanoseconds:100)
|
|
||||||
let C4 = TimeSpecification(seconds:100, nanoseconds:200)
|
|
||||||
test.eq(C1, C2, "Comparison Test 1")
|
|
||||||
test.ok(C2 < C3, "Comparison Test 2")
|
|
||||||
test.ok(C2 < C4, "Comparison Test 3")
|
|
||||||
|
|
||||||
// IntegerLiteralConvertible Tests
|
|
||||||
let I1 = TimeSpecification(integerLiteral:100)
|
|
||||||
let I2 = TimeSpecification(integerLiteral:-100)
|
|
||||||
test.eq(I1, TimeSpecification(seconds:100, nanoseconds:0), "Integer Literal Convertible Test 1")
|
|
||||||
test.eq(I2, TimeSpecification(seconds:-100, nanoseconds:0), "Integer Literal Convertible Test 2")
|
|
||||||
|
|
||||||
// FloatLiteralConvertible Tests
|
|
||||||
let F1 = TimeSpecification(floatLiteral:-1.1)
|
|
||||||
//// How to test...
|
|
||||||
|
|
||||||
// Sum and Difference Tests
|
|
||||||
let L1 = TimeSpecification(seconds:100, nanoseconds:123_456_789)
|
|
||||||
let R1 = TimeSpecification(seconds:100, nanoseconds:987_654_321)
|
|
||||||
test.eq(L1 + R1, TimeSpecification(seconds:201, nanoseconds:111_111_110), "Sum Test 1")
|
|
||||||
test.eq(L1 - R1, TimeSpecification(seconds:0, nanoseconds:-864_197_532), "Difference Test 1")
|
|
||||||
|
|
||||||
test.done(dontExit:true)
|
|
||||||
|
|
||||||
// Others
|
|
||||||
print("\nOTHERS")
|
|
||||||
print("C time(): \(time(nil))")
|
|
||||||
print("Calendar Clock: \(Clock.Calendar.timeSpecification()!)")
|
|
||||||
print("System Clock: \(Clock.System.timeSpecification()!)")
|
|
|
@ -57,7 +57,7 @@ public func <(lhs:TimeSpecification, rhs:TimeSpecification) -> Bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
/* IntegerLiteralConvertible */
|
/* ExpressibleByIntegerLiteral */
|
||||||
extension TimeSpecification {
|
extension TimeSpecification {
|
||||||
public typealias IntegerLiteralType = Int64
|
public typealias IntegerLiteralType = Int64
|
||||||
public init(integerLiteral value:Int64) {
|
public init(integerLiteral value:Int64) {
|
||||||
|
@ -66,7 +66,7 @@ extension TimeSpecification {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FloatLiteralConvertible */
|
/* ExpressibleByFloatLiteral */
|
||||||
extension TimeSpecification {
|
extension TimeSpecification {
|
||||||
public typealias FloatLiteralType = Double
|
public typealias FloatLiteralType = Double
|
||||||
public init(floatLiteral value:Double) {
|
public init(floatLiteral value:Double) {
|
|
@ -0,0 +1,6 @@
|
||||||
|
import XCTest
|
||||||
|
@testable import TimeSpecificationTests
|
||||||
|
|
||||||
|
XCTMain([
|
||||||
|
testCase(TimeSpecificationTests.allTests),
|
||||||
|
])
|
|
@ -0,0 +1,59 @@
|
||||||
|
/***************************************************************************************************
|
||||||
|
SwiftTimeSpecificationTests.swift
|
||||||
|
© 2016-2017 YOCKOW.
|
||||||
|
Licensed under MIT License.
|
||||||
|
See "LICENSE.txt" for more information.
|
||||||
|
**************************************************************************************************/
|
||||||
|
|
||||||
|
// FIXME: These are irresponsible tests below.
|
||||||
|
|
||||||
|
import XCTest
|
||||||
|
@testable import TimeSpecification
|
||||||
|
|
||||||
|
class TimeSpecificationTests: XCTestCase {
|
||||||
|
func testNormalization() {
|
||||||
|
let N1 = TimeSpecification(seconds:0, nanoseconds:1_234_567_890)
|
||||||
|
let N2 = TimeSpecification(seconds:-1, nanoseconds:-1_234_567_890)
|
||||||
|
|
||||||
|
XCTAssertTrue(N1.seconds == 1 && N1.nanoseconds == 234_567_890, "Normalization Test 1")
|
||||||
|
XCTAssertTrue(N2.seconds == -3 && N2.nanoseconds == 765_432_110, "Normalization Test 2")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testComparison() {
|
||||||
|
let C1 = TimeSpecification(seconds:100, nanoseconds:100)
|
||||||
|
let C2 = TimeSpecification(seconds: 98, nanoseconds:2_000_000_100)
|
||||||
|
let C3 = TimeSpecification(seconds:200, nanoseconds:100)
|
||||||
|
let C4 = TimeSpecification(seconds:100, nanoseconds:200)
|
||||||
|
XCTAssertEqual(C1, C2, "Comparison Test 1")
|
||||||
|
XCTAssertTrue(C2 < C3, "Comparison Test 2")
|
||||||
|
XCTAssertTrue(C2 < C4, "Comparison Test 3")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testIntegerLiteral() {
|
||||||
|
let I1: TimeSpecification = 100
|
||||||
|
let I2: TimeSpecification = -100
|
||||||
|
XCTAssertEqual(I1, TimeSpecification(seconds:100, nanoseconds:0), "ExpressibleByIntegerLiteral Test 1")
|
||||||
|
XCTAssertEqual(I2, TimeSpecification(seconds:-100, nanoseconds:0), "ExpressibleByIntegerLiteral Test 2")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testFloatLiteral() {
|
||||||
|
let F1: TimeSpecification = 1.1
|
||||||
|
XCTAssertEqual(F1, TimeSpecification(seconds:1, nanoseconds:100_000_000), "ExpressibleByFloatLiteral Test 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testSumAndDifference() {
|
||||||
|
let L1 = TimeSpecification(seconds:100, nanoseconds:123_456_789)
|
||||||
|
let R1 = TimeSpecification(seconds:100, nanoseconds:987_654_321)
|
||||||
|
XCTAssertEqual(L1 + R1, TimeSpecification(seconds:201, nanoseconds:111_111_110), "Sum Test 1")
|
||||||
|
XCTAssertEqual(L1 - R1, TimeSpecification(seconds:0, nanoseconds:-864_197_532), "Difference Test 1")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static var allTests = [
|
||||||
|
("Normalization", testNormalization),
|
||||||
|
("Comparison", testComparison),
|
||||||
|
("ExpressibleByIntegerLiteral", testIntegerLiteral),
|
||||||
|
("ExpressibleByFloatLiteral", testFloatLiteral),
|
||||||
|
("+/-", testSumAndDifference)
|
||||||
|
]
|
||||||
|
}
|
329
build-install.rb
329
build-install.rb
|
@ -2,138 +2,154 @@
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
build-install.rb
|
build-install.rb
|
||||||
© 2016 YOCKOW.
|
© 2016-2017 YOCKOW.
|
||||||
Licensed under MIT License.
|
Licensed under MIT License.
|
||||||
See "LICENSE.txt" for more information.
|
See "LICENSE.txt" for more information.
|
||||||
=end
|
=end
|
||||||
|
|
||||||
|
# Requirements #####################################################################################
|
||||||
require 'fileutils'
|
require 'fileutils'
|
||||||
require 'json'
|
require 'json'
|
||||||
require 'optparse'
|
require 'optparse'
|
||||||
require 'pathname'
|
require 'pathname'
|
||||||
|
require 'open3'
|
||||||
require 'shellwords'
|
require 'shellwords'
|
||||||
|
|
||||||
# Constants
|
# Constants ########################################################################################
|
||||||
OS = case RbConfig::CONFIG['host_os']
|
OS = case RbConfig::CONFIG['host_os']
|
||||||
when /darwin/i then :OS_X
|
when /darwin/i then :macOS
|
||||||
when /linux/i then :Linux
|
when /linux/i then :Linux
|
||||||
else :Other
|
else :Other
|
||||||
end
|
end
|
||||||
RequiredSwiftVersion = '3.0'
|
|
||||||
SharedLibraryPrefix = 'lib'
|
SharedLibraryPrefix = 'lib'
|
||||||
SharedLibrarySuffix = (OS == :OS_X) ? '.dylib' : '.so'
|
SharedLibrarySuffix = (OS == :macOS) ? '.dylib' : '.so'
|
||||||
SourcesDirectory = (Pathname(__FILE__).dirname + 'Sources').expand_path
|
|
||||||
LibrarySources = [
|
|
||||||
'Library'
|
|
||||||
].map{|fn| Pathname(fn)}
|
|
||||||
TestSources = [
|
|
||||||
'Test'
|
|
||||||
].map{|fn| Pathname(fn)}
|
|
||||||
ModuleName = 'TimeSpecification'
|
ModuleName = 'TimeSpecification'
|
||||||
ModuleLinkName = 'SwiftTimeSpecification'
|
ModuleLinkName = 'Swift' + ModuleName
|
||||||
|
RootDirectory = Pathname(__FILE__).dirname.expand_path
|
||||||
|
|
||||||
## Default Values
|
## Default Values ##
|
||||||
Defaults = {
|
Defaults = {
|
||||||
:swiftc => Pathname('swiftc'),
|
:swift => Pathname('swift'),
|
||||||
:build_directory => Pathname('build'),
|
:build_directory => Pathname('./build'),
|
||||||
:install => false,
|
:install => false,
|
||||||
:prefix => Pathname('/usr/local'),
|
:prefix => Pathname('/usr/local'),
|
||||||
|
:debug => false,
|
||||||
:skip_build => false,
|
:skip_build => false,
|
||||||
:skip_test => false,
|
:skip_test => false,
|
||||||
:sdk => 'macosx',
|
|
||||||
:clean => false
|
:clean => false
|
||||||
}
|
}
|
||||||
|
## Options ##
|
||||||
## Options
|
|
||||||
Options = {
|
Options = {
|
||||||
:swiftc => nil,
|
:swift => nil,
|
||||||
:build_directory => nil,
|
:build_directory => nil,
|
||||||
:install => nil,
|
:install => nil,
|
||||||
:prefix => nil,
|
:prefix => nil,
|
||||||
|
:debug => nil,
|
||||||
:skip_build => nil,
|
:skip_build => nil,
|
||||||
:skip_test => nil,
|
:skip_test => nil,
|
||||||
:sdk => nil,
|
:sdk => nil,
|
||||||
:clean => nil
|
:clean => nil
|
||||||
}
|
}
|
||||||
|
## Canceled ##
|
||||||
|
Canceled = {
|
||||||
|
:debug => nil,
|
||||||
|
:skip_build => nil,
|
||||||
|
:skip_test => nil
|
||||||
|
}
|
||||||
|
### Qualifications ###
|
||||||
|
UnsavableOptions = [:build_directory, :sdk, :clean]
|
||||||
|
PathnameOptions = [:ninja, :swift, :build_directory, :prefix]
|
||||||
|
|
||||||
# Functions
|
# Functions ########################################################################################
|
||||||
|
## Error ##
|
||||||
def failed(message)
|
def failed(message)
|
||||||
$stderr.puts(message)
|
$stderr.puts("!!ERROR!! #{message}")
|
||||||
exit
|
exit(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
def all_files_in_dir(dirname, basedir)
|
## Run Shell Script
|
||||||
files = []
|
def try_exec(command, indent = 0)
|
||||||
directory = basedir + dirname
|
puts(' ' * indent + "Execute: #{command}")
|
||||||
Dir.foreach(directory.to_s) {|filename|
|
Open3.popen3(command) {|stdin, stdout, stderr, wait_thread|
|
||||||
next if filename =~ /\A\.\.?\Z/
|
stdin.close
|
||||||
path = directory + filename
|
stdout.each {|line| $stdout.puts(' ' * indent * 2 + line) }
|
||||||
if path.directory?
|
stderr.each {|line| $stderr.puts(' ' * indent * 2 + line) }
|
||||||
files.concat(all_files_in_dir(filename, directory))
|
|
||||||
else
|
status = wait_thread.value.exitstatus
|
||||||
files.push(path)
|
failed("Command exited with status #{status}") if status != 0
|
||||||
end
|
|
||||||
}
|
}
|
||||||
return files
|
|
||||||
end
|
|
||||||
def all_files(list, rootdir)
|
|
||||||
files = []
|
|
||||||
list.each {|filename|
|
|
||||||
path = rootdir + filename
|
|
||||||
failed("#{path.to_s}: No such file or directory.") if !path.exist?
|
|
||||||
if path.directory?
|
|
||||||
files.concat(all_files_in_dir(filename, rootdir))
|
|
||||||
elsif
|
|
||||||
files.push(path)
|
|
||||||
end
|
|
||||||
}
|
|
||||||
return files
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Extends class
|
# Extends Class(es) ################################################################################
|
||||||
|
## Pathname ##
|
||||||
class Pathname
|
class Pathname
|
||||||
def escaped
|
def escaped(type = :shell)
|
||||||
return Shellwords.shellescape(self.to_s)
|
return Shellwords.shellescape(self.to_s) if type == :shell
|
||||||
|
return self.to_s.gsub(/\$/, '$$').gsub(/\s/, '$\&') if type == :ninja
|
||||||
|
return self.to_s
|
||||||
|
end
|
||||||
|
def exit_if_i_am_file
|
||||||
|
failed("#{self.to_s} is not directory.") if self.exist? && !self.directory?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Parsing Options
|
# Parse Options ####################################################################################
|
||||||
OptionParser.new(__FILE__){|parser|
|
OptionParser.new(__FILE__){|parser|
|
||||||
parser.on('--swiftc=PATH',
|
parser.on('--swift=PATH',
|
||||||
'Path to the Swift compiler which you want to use.') {|path|
|
'Path to `swift` which you want to use.') {|path|
|
||||||
Options[:swiftc] = Pathname(path)
|
path = Pathname(path)
|
||||||
|
path += 'swift' if path.directory?
|
||||||
|
Options[:swift] = Pathname(path)
|
||||||
}
|
}
|
||||||
parser.on('--build-dir=PATH', '--build-directory=PATH',
|
parser.on('--build-dir=PATH', '--build-directory=PATH',
|
||||||
'Name of the directory where the build products will be placed.') {|path|
|
'Name of the directory where the build products will be placed. ' +
|
||||||
|
'Default: ' + Defaults[:build_directory].to_s) {|path|
|
||||||
Options[:build_directory] = Pathname(path)
|
Options[:build_directory] = Pathname(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.on('--install',
|
parser.on('--install',
|
||||||
'Whether to install products or not.') {|value|
|
'Whether to install products or not.') {|value|
|
||||||
Options[:install] = value
|
Options[:install] = value
|
||||||
}
|
}
|
||||||
parser.on('--prefix=PATH', '--install-prefix=PATH',
|
parser.on('--prefix=PATH', '--install-prefix=PATH',
|
||||||
'The installation prefix.') {|path|
|
'The installation prefix. (Only used when `--install` is specified.) ' +
|
||||||
|
'Default: ' + Defaults[:prefix].to_s) {|path|
|
||||||
Options[:prefix] = Pathname(path)
|
Options[:prefix] = Pathname(path)
|
||||||
Options[:prefix]= Options[:prefix].expand_path if path =~ /\A~\//
|
Options[:prefix]= Options[:prefix].expand_path if path =~ /\A~\//
|
||||||
if !Options[:prefix].absolute?
|
if !Options[:prefix].absolute?
|
||||||
failed(%Q[The installation prefix must be absolute path.])
|
failed(%Q[The installation prefix must be absolute path.])
|
||||||
elsif Options[:prefix].exist? && !Options[:prefix].directory?
|
|
||||||
failed(%Q["#{path}" is not directory.])
|
|
||||||
end
|
end
|
||||||
|
Options[:prefix].exit_if_i_am_file
|
||||||
|
Options[:install] = true # install library if prefix is specified.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parser.on('--debug',
|
||||||
|
'Debug builds') {|value|
|
||||||
|
Options[:debug] = value
|
||||||
|
}
|
||||||
|
parser.on('--release',
|
||||||
|
'Release builds; default is on') {|value|
|
||||||
|
Canceled[:debug] = value
|
||||||
|
}
|
||||||
|
|
||||||
parser.on('--skip-build',
|
parser.on('--skip-build',
|
||||||
'Whether to skip building or not.') {|value|
|
'Whether to skip building or not.') {|value|
|
||||||
Options[:skip_build] = value
|
Options[:skip_build] = value
|
||||||
}
|
}
|
||||||
|
parser.on('--do-build',
|
||||||
|
'Cancel skipping building') {|value|
|
||||||
|
Canceled[:skip_build] = value
|
||||||
|
}
|
||||||
|
|
||||||
parser.on('--skip-test',
|
parser.on('--skip-test',
|
||||||
'Whether to skip testing or not.') {|value|
|
'Whether to skip testing or not.') {|value|
|
||||||
Options[:skip_test] = value
|
Options[:skip_test] = value
|
||||||
}
|
}
|
||||||
parser.on('--sdk=VALUE',
|
parser.on('--do-test',
|
||||||
'(OS X Only) SDK name to be passed to `xcrun`.'){|value|
|
'Cancel skipping testing') {|value|
|
||||||
Options[:sdk] = value
|
Canceled[:skip_test] = value
|
||||||
failed("Invalid SDK Name: #{sdk}") if sdk !~ /\A[\.0-9A-Z_a-z]+\Z/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
parser.on('--clean',
|
parser.on('--clean',
|
||||||
'Whether to clean up or not.') {|value|
|
'Whether to clean up or not.') {|value|
|
||||||
Options[:clean] = value
|
Options[:clean] = value
|
||||||
|
@ -146,43 +162,27 @@ OptionParser.new(__FILE__){|parser|
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
# Set SDK Name if it's nil
|
# Determine Options ################################################################################
|
||||||
Options[:sdk] = Defaults[:sdk] if OS == :OS_X && Options[:sdk].nil?
|
UnsavableOptions.each{|key| Options[key] = Defaults[key] if Options[key].nil?}
|
||||||
|
|
||||||
# Check SDK Name
|
## Build Directory
|
||||||
if OS == :OS_X && !system(%Q[xcrun --sdk #{Options[:sdk]} --show-sdk-path >/dev/null 2>&1])
|
|
||||||
if $?.exitstatus == 127
|
|
||||||
failed("'xcrun' does not exist.")
|
|
||||||
else
|
|
||||||
failed("Invalid SDK Name: #{Options[:sdk]}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Build Directory
|
|
||||||
def exit_if_path_is_not_directory(path)
|
|
||||||
failed(%Q["#{path.to_s}" is Not Directory]) if path.exist? && !path.directory?
|
|
||||||
end
|
|
||||||
Options[:build_directory] = Defaults[:build_directory] if Options[:build_directory].nil?
|
Options[:build_directory] = Defaults[:build_directory] if Options[:build_directory].nil?
|
||||||
Options[:build_directory] = Options[:build_directory].expand_path if Options[:build_directory].relative?
|
Options[:build_directory] = RootDirectory + Options[:build_directory] if Options[:build_directory].relative?
|
||||||
exit_if_path_is_not_directory(Options[:build_directory])
|
Options[:build_directory].exit_if_i_am_file
|
||||||
Options[:build_directory] += Options[:sdk] if !Options[:sdk].nil?
|
|
||||||
exit_if_path_is_not_directory(Options[:build_directory])
|
|
||||||
FileUtils.rm_r(Options[:build_directory].to_s) if Options[:clean]
|
FileUtils.rm_r(Options[:build_directory].to_s) if Options[:clean]
|
||||||
FileUtils.mkdir_p(Options[:build_directory].to_s)
|
FileUtils.mkdir_p(Options[:build_directory].to_s)
|
||||||
|
|
||||||
# Set Options from defaults
|
## Save/Read Cache
|
||||||
cache_txt = Options[:build_directory] + 'build_options-cache.txt'
|
cache_json = Options[:build_directory] + 'build_options-cache.json'
|
||||||
saved_defaults = nil
|
saved_defaults = nil
|
||||||
if cache_txt.exist?
|
if cache_json.exist?
|
||||||
saved_defaults = JSON.parse(File.read(cache_txt.to_s), {:symbolize_names => true})
|
saved_defaults = JSON.parse(File.read(cache_json.to_s), {:symbolize_names => true})
|
||||||
saved_defaults.each_key{|key|
|
saved_defaults.each_key{|key|
|
||||||
if key == :build_directory || key == :swiftc || key == :prefix
|
saved_defaults[key] = Pathname(saved_defaults[key]) if PathnameOptions.include?(key)
|
||||||
saved_defaults[key] = Pathname(saved_defaults[key])
|
|
||||||
end
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
Defaults.each_pair{|key, value|
|
Defaults.each_pair{|key, value|
|
||||||
next if key == :sdk || key == :build_directory || key == :clean
|
next if UnsavableOptions.include?(key)
|
||||||
if Options[key].nil?
|
if Options[key].nil?
|
||||||
if !saved_defaults.nil? && !saved_defaults[key].nil?
|
if !saved_defaults.nil? && !saved_defaults[key].nil?
|
||||||
Options[key] = saved_defaults[key]
|
Options[key] = saved_defaults[key]
|
||||||
|
@ -191,126 +191,59 @@ Defaults.each_pair{|key, value|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
File.write(cache_txt.to_s, JSON.dump(Options))
|
Canceled.each_pair{|key, value|
|
||||||
|
Options[key] = false if !value.nil? && value
|
||||||
|
}
|
||||||
|
File.write(cache_json.to_s, JSON.dump(Options))
|
||||||
|
Options.each_pair {|key, value| Options[key] = Defaults[key] if value.nil? }
|
||||||
|
|
||||||
# Determine Swift Path
|
# Swift? ###########################################################################################
|
||||||
if !system(%Q[which #{Options[:swiftc].escaped} >/dev/null])
|
failed("#{Options[:swift]} is not found.") if !system(%Q[which #{Options[:swift].escaped} >/dev/null])
|
||||||
failed("`swiftc` is not found.")
|
|
||||||
end
|
|
||||||
swiftc_command =
|
|
||||||
(OS == :OS_X) ? "xcrun --sdk #{Options[:sdk]} #{Options[:swiftc].escaped}"
|
|
||||||
: Options[:swiftc].escaped
|
|
||||||
|
|
||||||
# Detect Swift Version
|
# Build! ###########################################################################################
|
||||||
swift_version = %x[#{swiftc_command} --version]
|
configuration = Options[:debug] ? 'debug' : 'release'
|
||||||
if swift_version =~ /^(?:Apple\s+)?Swift\s+version\s+(\d+)((?:\.\d+)*)\s+/
|
|
||||||
swift_version = Regexp.last_match(1) + Regexp.last_match(2)
|
|
||||||
if (swift_version.split('.').map(&:to_i) <=> RequiredSwiftVersion.split('.').map(&:to_i)) < 0
|
|
||||||
failed("The minimum required version of Swift is #{RequiredSwiftVersion}")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
failed("Cannot detect the version of Swift: #{swift_version}")
|
|
||||||
end
|
|
||||||
|
|
||||||
# Print Options
|
libFilename = Pathname(SharedLibraryPrefix + ModuleLinkName + SharedLibrarySuffix)
|
||||||
puts("Options:")
|
libPath = Options[:build_directory] + Pathname(configuration) + libFilename
|
||||||
puts(%Q[ Swift Compiler: #{Options[:swiftc].to_s}])
|
moduleFilename = Pathname(ModuleName + '.swiftmodule')
|
||||||
puts(%Q[ Swift Version: #{swift_version}])
|
modulePath = Options[:build_directory] + Pathname(configuration) + moduleFilename
|
||||||
puts(%Q[ The Build Directory: "#{Options[:build_directory].to_s}"])
|
|
||||||
if Options[:install]
|
|
||||||
puts(%Q[ The Installation Prefix: "#{Options[:prefix].to_s}"])
|
|
||||||
else
|
|
||||||
puts(%Q[ No products will be installed.])
|
|
||||||
end
|
|
||||||
puts(%Q[ Skip building: #{Options[:skip_build] ? "Yes" : "No"}])
|
|
||||||
puts(%Q[ Skip testing: #{Options[:skip_test] ? "Yes" : "No"}])
|
|
||||||
|
|
||||||
# Create directories
|
# Build
|
||||||
build_include_directory = Options[:build_directory] + 'include'
|
|
||||||
build_lib_directory = Options[:build_directory] + 'lib'
|
|
||||||
if !Options[:skip_build] || !Options[:skip_test]
|
|
||||||
FileUtils.mkdir_p(Options[:build_directory].to_s) if !File.exists?(Options[:build_directory])
|
|
||||||
FileUtils.mkdir_p(build_include_directory.to_s) if !File.exists?(build_include_directory)
|
|
||||||
FileUtils.mkdir_p(build_lib_directory.to_s) if !File.exists?(build_lib_directory)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Let's Start!
|
|
||||||
def try_exec(command)
|
|
||||||
puts(" Execute: #{command}")
|
|
||||||
if !system(command)
|
|
||||||
failed("Command exited with status #{$?.exitstatus}")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
## BUILD
|
|
||||||
if !Options[:skip_build]
|
if !Options[:skip_build]
|
||||||
puts("===== BUILD =====")
|
puts("[Start Building...]")
|
||||||
|
try_exec(["swift build --build-path #{Options[:build_directory].escaped()}",
|
||||||
library_sources = all_files(LibrarySources, SourcesDirectory)
|
"--configuration #{configuration}",
|
||||||
|
"-Xswiftc -emit-library -Xswiftc -o#{libPath.escaped()}",
|
||||||
create_module =
|
"-Xswiftc -module-link-name -Xswiftc #{ModuleLinkName}",
|
||||||
"#{swiftc_command} " +
|
"-Xswiftc -module-name -Xswiftc #{ModuleName}",
|
||||||
library_sources.map{|file| file.escaped}.join(' ') + ' ' +
|
"-Xswiftc -emit-module-path -Xswiftc #{modulePath.escaped()}"].join(" "),
|
||||||
"-module-name #{ModuleName} " +
|
2)
|
||||||
"-module-link-name #{ModuleLinkName} " +
|
puts()
|
||||||
"-emit-module-path #{build_include_directory.escaped}/#{ModuleName}.swiftmodule "
|
|
||||||
try_exec(create_module)
|
|
||||||
|
|
||||||
build_library =
|
|
||||||
"#{swiftc_command} " +
|
|
||||||
library_sources.map{|file| file.escaped}.join(' ') + ' ' +
|
|
||||||
"-module-name #{ModuleName} " +
|
|
||||||
"-emit-library " +
|
|
||||||
"-o#{build_lib_directory.escaped}/#{SharedLibraryPrefix}#{ModuleLinkName}#{SharedLibrarySuffix}"
|
|
||||||
try_exec(build_library)
|
|
||||||
|
|
||||||
puts("...DONE")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
## TEST
|
# Test
|
||||||
if !Options[:skip_test]
|
if !Options[:skip_test]
|
||||||
puts("===== TEST =====")
|
if !Options[:debug]
|
||||||
|
$stderr.puts("** WARNING ** No tests will be executed when `release` mode is specified.\n")
|
||||||
test_executable = Options[:build_directory] + 'test'
|
else
|
||||||
test_sources = all_files(TestSources, SourcesDirectory)
|
puts("[Start Testing...]")
|
||||||
|
try_exec(["swift test --build-path #{Options[:build_directory].escaped()}",
|
||||||
if !test_executable.exist?
|
"--configuration #{configuration}"].join(" "), 2)
|
||||||
puts("Start building an executable")
|
|
||||||
build_test =
|
|
||||||
"#{swiftc_command} " +
|
|
||||||
test_sources.map{|file| file.escaped}.join(' ') + ' ' +
|
|
||||||
"-o#{test_executable.escaped} " +
|
|
||||||
"-I#{build_include_directory.escaped} " +
|
|
||||||
"-L#{build_lib_directory.escaped}"
|
|
||||||
try_exec(build_test)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
puts("Start tests")
|
|
||||||
if !system(%Q[LD_LIBRARY_PATH=#{build_lib_directory.escaped} #{test_executable.escaped}])
|
|
||||||
failed("TEST FAILED.")
|
|
||||||
end
|
|
||||||
|
|
||||||
puts("..SUCCESSFUL")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
## INSTALL
|
# Install
|
||||||
if Options[:install]
|
if !Options[:install]
|
||||||
puts("===== INSTALL =====")
|
puts("[Installing...]")
|
||||||
|
|
||||||
include_directory = Options[:prefix] + 'include'
|
if Options[:debug]
|
||||||
lib_directory = Options[:prefix] + 'lib'
|
$stderr.puts("** WARNING ** DEBUG MODE. Products to be installed may not be optimized.\n")
|
||||||
|
|
||||||
FileUtils.mkdir_p(include_directory.to_s) if !File.exists?(include_directory)
|
|
||||||
FileUtils.mkdir_p(lib_directory.to_s) if !File.exists?(lib_directory)
|
|
||||||
|
|
||||||
begin
|
|
||||||
FileUtils.copy_entry(build_include_directory.to_s,
|
|
||||||
include_directory.to_s)
|
|
||||||
FileUtils.copy_entry(build_lib_directory.to_s,
|
|
||||||
lib_directory.to_s)
|
|
||||||
rescue
|
|
||||||
failed("Installation Failed.")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
puts("...DONE.")
|
libInstallPath = Options[:prefix] + Pathname('lib') + libFilename
|
||||||
|
moduleInstallPath = Options[:prefix] + Pathname('include') + moduleFilename
|
||||||
|
|
||||||
|
try_exec("cp #{libPath.escaped()} #{libInstallPath.escaped()} && " +
|
||||||
|
"cp #{modulePath.escaped()} #{moduleInstallPath.escaped()}", 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue