Commit 1dacf5c3 authored by Drew's avatar Drew

Merge pull request #25 from AnarchyTools/foundation-removal

Foundation removal
parents cc4c4353 5a808267
Pipeline #1696 passed with stage
......@@ -5,7 +5,8 @@ linux:
stage: build
script:
- apt-get update
- apt-get install --no-install-recommends xz-utils curl ca-certificates -y
- apt-get install --no-install-recommends xz-utils curl ca-certificates git -y
- git submodule init && git submodule update
- curl -L https://github.com/AnarchyTools/atbuild/releases/download/0.9.0/atbuild-0.9.0-linux.tar.xz | tar xJ -C /usr/local
- atbuild check
tags:
......@@ -15,6 +16,7 @@ linux:
osx:
stage: build
script:
- git submodule init && git submodule update
- atbuild check
tags:
- openswift
......
[submodule "atfoundation"]
path = atfoundation
url = https://github.com/AnarchyTools/atfoundation.git
Subproject commit 3583e40ec5d288efdceded9b8f6b6ab3dcc84249
{
"folders":
[
{
"path": ".",
"folder_exclude_patterns": [ ".atllbuild", "bin", "user" ],
"file_exclude_patterns": [ ".gitignore", ".gitlab-ci.yml", "Dockerfile", "LICENSE" ]
},
]
}
......@@ -15,13 +15,17 @@
(package
:name "atpkg"
:import-packages ["atfoundation/build.atpkg"]
:tasks {
:atpkg {
:tool "atllbuild"
:sources ["src/**.swift"]
:name "atpkg"
:output-type "static-library"
:link-with ["atfoundation.a"]
:dependencies ["atfoundation.atfoundation"]
:publish-product true
:overlays {
:bootstrap-osx {
......@@ -39,11 +43,11 @@
:atpkg-tests {
:tool "atllbuild"
:dependencies ["atpkg"]
:dependencies ["atpkg" "atfoundation.atfoundation"]
:sources ["tests/**.swift"]
:name "atpkgtests"
:output-type "executable"
:link-with ["atpkg.a"]
:link-with ["atpkg.a" "atfoundation.a"]
:publish-product true
}
......
......@@ -11,28 +11,28 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
import atfoundation
/**
* This function resolves wildcards in source descriptions to complete values
* - parameter sourceDescriptions: a descriptions of sources such as ["src/**.swift"] */
* - parameter taskForCalculatingPath: A task relative to which we calculate the path (to handle the import case). If nil, we return what is listed in the atpkg.
* - returns: A list of resolved sources such as ["src/a.swift", "src/b.swift"]
*/
public func collectSources(sourceDescriptions: [String], taskForCalculatingPath task: Task?) -> [String] {
var sources : [String] = []
public func collectSources(sourceDescriptions: [String], taskForCalculatingPath task: Task?) -> [Path] {
var sources : [Path] = []
for unPrefixedDescription in sourceDescriptions {
let description = (task?.importedPath ?? "") + unPrefixedDescription
if description.hasSuffix("**.swift") {
let basepath = String(Array(description.characters)[0..<description.characters.count - 9])
let manager = NSFileManager.defaultManager()
guard let enumerator = manager.enumerator(atPath: basepath) else {
fatalError("Invalid path \(basepath)")
}
while let source_ns = enumerator.nextObject() as? NSString {
let source = source_ns.toString
if source.hasSuffix("swift") {
sources.append(basepath + "/" + source)
let description = (task?.importedPath ?? Path()) + unPrefixedDescription
if unPrefixedDescription.hasSuffix("**.swift") {
let basepath = description.dirname()
do {
let iterator = try FS.iterateItems(path: basepath, recursive: true)
for file in iterator {
if file.path.components.last!.hasSuffix(".swift") {
sources.append(file.path)
}
}
} catch {
fatalError("Error: \(error) for '\(basepath)'")
}
}
else {
......
......@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import atfoundation
final public class ExternalDependency {
public enum VersioningMethod {
case Version([String])
......@@ -20,34 +22,37 @@ final public class ExternalDependency {
case Tag(String)
}
public var gitURL: String
public var gitURL: URL
public var version: VersioningMethod
public var name: String {
let lastComponent = gitURL.toNSString.lastPathComponent
if lastComponent.hasSuffix(".git") {
return lastComponent.toNSString.substring(to: lastComponent.characters.count - 4)
if let lastComponent = gitURL.path.components.last {
if lastComponent.hasSuffix(".git") {
return lastComponent.subString(toIndex: lastComponent.endIndex.advanced(by: -4))
}
return lastComponent
} else {
return "unknown"
}
return lastComponent
}
init?(url: String, version: [String]) {
self.gitURL = url
self.gitURL = URL(string: url)
self.version = .Version(version)
}
init?(url: String, commit: String) {
self.gitURL = url
self.gitURL = URL(string: url)
self.version = .Commit(commit)
}
init?(url: String, branch: String) {
self.gitURL = url
self.gitURL = URL(string: url)
self.version = .Branch(branch)
}
init?(url: String, tag: String) {
self.gitURL = url
self.gitURL = URL(string: url)
self.version = .Tag(tag)
}
}
\ No newline at end of file
// Copyright (c) 2016 Anarchy Tools Contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
//SR-138
extension String {
var toNSString: NSString {
#if os(Linux)
return self.bridge()
#elseif os(OSX)
return (self as NSString)
#endif
}
#if os(Linux)
public func substring(with range: Range<String.Index>) -> String {
var result = ""
result.reserveCapacity(range.count)
for idx in range {
result.append(self.characters[idx])
}
return result
}
public func substring(to index: Int) -> String {
return self.substring(with: self.startIndex..<self.startIndex.advanced(by:index))
}
#endif
}
extension NSString {
var toString: String {
#if os(Linux)
return self.bridge()
#elseif os(OSX)
return (self as String)
#endif
}
}
// These parts of the "great swift renaming" are not yet implemented on Linux
#if os(Linux)
extension NSFileManager {
func enumerator(atPath path: String) -> NSDirectoryEnumerator? {
return self.enumeratorAtPath(path)
}
func createSymbolicLink(atPath path: String, withDestinationPath destPath: String) throws {
return try self.createSymbolicLinkAtPath(path, withDestinationPath: destPath)
}
func createDirectory(atPath path: String, withIntermediateDirectories createIntermediates: Bool, attributes: [String : AnyObject]? = [:]) throws {
return try self.createDirectoryAtPath(path, withIntermediateDirectories: createIntermediates, attributes: attributes)
}
func attributesOfItem(atPath path: String) throws -> [String : Any] {
return try self.attributesOfItemAtPath(path)
}
func removeItem(atPath path: String) throws {
return try self.removeItemAtPath(path)
}
func fileExists(atPath path: String) -> Bool {
return self.fileExistsAtPath(path)
}
}
extension NSCharacterSet {
class func letters() -> NSCharacterSet {
return self.letterCharacterSet()
}
class func whitespaces() -> NSCharacterSet {
return self.whitespaceCharacterSet()
}
}
extension NSString {
var deletingLastPathComponent: String {
return self.stringByDeletingLastPathComponent
}
func substring(to index: Int) -> String {
return self.substringToIndex(index)
}
}
#endif
......@@ -11,7 +11,8 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
import atfoundation
enum PackageError: ErrorProtocol {
case NonVectorImport
......@@ -111,7 +112,7 @@ final public class Package {
public var tasks: [String:Task] = [:]
public var externals: [ExternalDependency] = []
public var importedPath: String
public var importedPath: Path
///Overlays that are a (direct) child of the receiver. These are indexed by unqualified name.
private var childOverlays: [String: [String: ParseValue]] = [:]
......@@ -128,7 +129,7 @@ final public class Package {
return arr
}
var adjustedImportPath: String = ""
var adjustedImportPath: Path = Path()
/**Calculate the pruned dependency graph for the given task
- returns: A list of tasks in a reasonable order to be processed. */
......@@ -155,13 +156,15 @@ final public class Package {
- parameter overlay: A list of overlays to apply globally to all tasks in the package.
- parameter focusOnTask: The user has "selected" the particular task. We provide more diagnostics for this task.
*/
public convenience init(filepath: String, overlay: [String], focusOnTask: String?) throws {
public convenience init(filepath: Path, overlay: [String], focusOnTask: String?) throws {
//todo: why doesn't this throw?
guard let parser = Parser(filepath: filepath) else { throw PackageError.ParserFailed }
guard let parser = try Parser(filepath: filepath) else {
throw PackageError.ParserFailed
}
let result = try parser.parse()
let basepath = filepath.toNSString.deletingLastPathComponent
let basepath = filepath.dirname()
try self.init(type: result, overlay: overlay, pathOnDisk:basepath, focusOnTask: focusOnTask)
}
......@@ -170,7 +173,7 @@ final public class Package {
- parameter pathOnDisk: The path to the file on disk. This does not include the file name.
- parameter focusOnTask: The user has "selected" the particular task. We provide more diagnostics for this task.
*/
public init(type: ParseType, overlay requestedGlobalOverlays: [String], pathOnDisk: String, focusOnTask: String?) throws {
public init(type: ParseType, overlay requestedGlobalOverlays: [String], pathOnDisk: Path, focusOnTask: String?) throws {
//warn on unknown keys
for (k,_) in type.properties {
if !Key.allKeys.map({$0.rawValue}).contains(k) {
......@@ -179,7 +182,7 @@ final public class Package {
}
if type.name != "package" { throw PackageError.NonPackage }
self.importedPath = pathOnDisk.pathWithTrailingSlash
self.importedPath = pathOnDisk
if let value = type.properties[Key.Name.rawValue]?.string { self.name = value }
else {
......@@ -205,9 +208,8 @@ final public class Package {
}
for importFile in imports {
guard let importFileString = importFile.string else { fatalError("Non-string import \(importFile)")}
let adjustedImportPath = (pathOnDisk.pathWithTrailingSlash + importFileString).toNSString.deletingLastPathComponent.pathWithTrailingSlash
let adjustedFileName = importFileString.toNSString.lastPathComponent
let remotePackage = try Package(filepath: adjustedImportPath + adjustedFileName, overlay: requestedGlobalOverlays, focusOnTask: nil)
let adjustedImportPath = (pathOnDisk + importFileString).dirname()
let remotePackage = try Package(filepath: pathOnDisk + importFileString, overlay: requestedGlobalOverlays, focusOnTask: nil)
remotePackage.adjustedImportPath = adjustedImportPath
remotePackages.append(remotePackage)
}
......@@ -242,10 +244,9 @@ final public class Package {
let importFileString = "external/" + externalDep.name + "/build.atpkg"
// import the atbuild file if it is there
let adjustedImportPath = (pathOnDisk.pathWithTrailingSlash + importFileString).toNSString.deletingLastPathComponent.pathWithTrailingSlash
let adjustedFileName = importFileString.toNSString.lastPathComponent
let adjustedImportPath = (pathOnDisk + importFileString).dirname()
do {
let remotePackage = try Package(filepath: adjustedImportPath + adjustedFileName, overlay: requestedGlobalOverlays, focusOnTask: nil)
let remotePackage = try Package(filepath: pathOnDisk + importFileString, overlay: requestedGlobalOverlays, focusOnTask: nil)
remotePackage.adjustedImportPath = adjustedImportPath
remotePackages.append(remotePackage)
} catch PackageError.ParserFailed {
......
// Copyright (c) 2016 Anarchy Tools Contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
extension String {
var pathWithTrailingSlash: String {
if self.hasSuffix("/") { return self }
else if self.characters.count > 0 { return self + "/" }
else {
//some clients, like collectSources, need relative paths. We shouldn't insert an absolute path if we didn't get one.
return ""
}
}
}
\ No newline at end of file
......@@ -26,7 +26,7 @@ private func evaluateSubstitution(substitution: String, package: Package) -> Str
let collectedSources = collectSources(sourceDescriptions: str_sources, taskForCalculatingPath: task)
var output = ""
for (idx, source) in collectedSources.enumerated() {
output += source
output += source.description
if idx != collectedSources.count - 1 { output += " "}
}
return output
......
......@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import atfoundation
final public class Task {
///The unqualified name of the task, not including its package name
public let unqualifiedName: String
......@@ -26,15 +28,15 @@ final public class Task {
public var dependencies: [String] = []
public var tool: String
public var importedPath: String ///the directory at which the task was imported. This includes a trailing /.
public var importedPath: Path /// the directory at which the task was imported
var overlay: [String] = [] ///The overlays we should apply to this task
internal(set) public var appliedOverlays: [String] = [] ///The overlays we did apply to this task
var declaredOverlays: [String: [String: ParseValue]] = [:] ///The overlays this task declares
public var allKeys: [String]
private var kvp: [String:ParseValue]
public enum Option: String {
......@@ -53,10 +55,10 @@ final public class Task {
}
}
init?(value: ParseValue, unqualifiedName: String, package: Package, importedPath: String) {
init?(value: ParseValue, unqualifiedName: String, package: Package, importedPath: Path) {
precondition(!unqualifiedName.characters.contains("."), "Task \(unqualifiedName) may not contain a period.")
guard let kvp = value.map else { return nil }
self.importedPath = importedPath.pathWithTrailingSlash
self.importedPath = importedPath
self.kvp = kvp
self.unqualifiedName = unqualifiedName
self.package = package
......@@ -98,7 +100,7 @@ final public class Task {
}
}
}
public subscript(key: String) -> ParseValue? {
get {
return kvp[key]
......
......@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
import atfoundation
public enum ParseError: ErrorProtocol {
case InvalidPackageFile
......@@ -25,7 +25,7 @@ public enum ParseValue {
case IntegerLiteral(Int)
case FloatLiteral(Double)
case BoolLiteral(Bool)
case Map([String:ParseValue])
case Vector([ParseValue])
}
......@@ -35,7 +35,7 @@ extension ParseValue {
if case let .StringLiteral(value) = self { return value }
return nil
}
public var integer: Int? {
if case let .IntegerLiteral(value) = self { return value }
return nil
......@@ -50,12 +50,12 @@ extension ParseValue {
if case let .BoolLiteral(value) = self { return value }
return nil
}
public var map: [String:ParseValue]? {
if case let .Map(value) = self { return value }
return nil
}
public var vector: [ParseValue]? {
if case let .Vector(value) = self { return value }
return nil
......@@ -70,7 +70,7 @@ final public class ParseType {
final public class Parser {
let lexer: Lexer
private func next() -> Token? {
while true {
guard let token = lexer.next() else { return nil }
......@@ -79,19 +79,19 @@ final public class Parser {
}
}
}
public init?(filepath: String) {
guard let content = try? NSString(contentsOfFile: filepath, encoding: NSUTF8StringEncoding) else {
public init?(filepath: Path) throws {
guard let content = try String(loadFromFile: filepath) else {
return nil
}
let scanner = Scanner(content: content.toString)
let scanner = Scanner(content: content)
self.lexer = Lexer(scanner: scanner)
}
public func parse() throws -> ParseType {
guard let token = next() else { throw ParseError.InvalidPackageFile }
if token.type == .OpenParen {
return try parseType()
}
......@@ -99,48 +99,48 @@ final public class Parser {
throw ParseError.ExpectedTokenType(.OpenParen, token)
}
}
private func parseType() throws -> ParseType {
let type = ParseType()
type.name = try parseIdentifier()
type.properties = try parseKeyValuePairs()
return type
}
private func parseKeyValuePairs() throws -> [String:ParseValue] {
var pairs: [String:ParseValue] = [:]
while let token = next() where token.type != .CloseParen && token.type != .CloseBrace {
lexer.stall()
let key = try parseKey()
let value = try parseValue()
pairs[key] = value
}
lexer.stall()
return pairs
}
private func parseKey() throws -> String {
let colon = next()
if colon?.type != .Colon { throw ParseError.ExpectedTokenType(.Colon, lexer.peek()) }
return try parseIdentifier()
}
private func parseIdentifier() throws -> String {
guard let identifier = next() else { throw ParseError.ExpectedTokenType(.Identifier, lexer.peek()) }
if identifier.type != .Identifier { throw ParseError.ExpectedTokenType(.Identifier, lexer.peek()) }
return identifier.value
}
private func parseValue() throws -> ParseValue {
guard let token = next() else { throw ParseError.InvalidTokenForValueType(nil) }
switch token.type {
case .OpenBrace: lexer.stall(); return try parseMap()
case .OpenBracket: lexer.stall(); return try parseVector()
......@@ -150,11 +150,11 @@ final public class Parser {
default: throw ParseError.InvalidTokenForValueType(token)
}
}
private func parseVector() throws -> ParseValue {
if let token = next() where token.type != .OpenBracket { throw ParseError.ExpectedTokenType(.OpenBracket, token) }
var items: [ParseValue] = []
while let token = next() where token.type != .CloseBracket {
lexer.stall()
items.append(try parseValue())
......@@ -165,12 +165,12 @@ final public class Parser {
return .Vector(items)
}
private func parseMap() throws -> ParseValue {
if let token = next() where token.type != .OpenBrace { throw ParseError.ExpectedTokenType(.OpenBrace, token) }
let items = try parseKeyValuePairs()
if let token = next() where token.type != .CloseBrace { throw ParseError.ExpectedTokenType(.CloseBrace, token) }
return .Map(items)
}
}
......@@ -19,7 +19,7 @@ public struct ScannerInfo {
}
final public class Scanner {
var content: String
var index: String.Index
var current: ScannerInfo? = nil
......@@ -27,7 +27,7 @@ final public class Scanner {
private var shouldStall = false
var line: Int = 1
var column: Int = 1
var column: Int = 1
public init(content: String) {
self.content = content
......@@ -52,9 +52,9 @@ final public class Scanner {
shouldStall = false
return current
}
if index == content.endIndex {
current = nil
current = nil
}
else {
current = ScannerInfo(character: content[index], line: line, column: column)
......@@ -62,14 +62,14 @@ final public class Scanner {
if current?.character == "\n" {
line += 1
column = 1
column = 1
}
else {
column += 1
}
}
return current
return current
}
public func peek() -> ScannerInfo? {
......
......@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
import atfoundation
public enum TokenType {
case Identifier
......@@ -52,27 +52,25 @@ public struct Token: Equatable {
}
}
func isCharacterPartOfSet(c: Character?, set: NSCharacterSet) -> Bool {
guard let c = c else { return false }
var isMember = true
for utf16Component in String(c).utf16 {
if !set.characterIsMember(utf16Component) { isMember = false; break }
}
return isMember
}
func isValidIdentifierSignalCharacter(c: Character?) -> Bool {
return isCharacterPartOfSet(c: c, set: NSCharacterSet.letters())
guard let c = c else {
return false
}
return Charset.isLetter(character: c)
}
func isValidIdenitifierCharacter(c: Character?) -> Bool {
return isCharacterPartOfSet(c: c, set: NSCharacterSet.letters()) || c == "-" || c == "." || c == "/"
guard let c = c else {
return false
}
return Charset.isLetter(character: c) || c == "-" || c == "." || c == "/"
}
func isWhitespace(c: Character?) -> Bool {
return isCharacterPartOfSet(c: c, set: NSCharacterSet.whitespaces())
guard let c = c else {
return false
}
return Charset.isWhitespace(character: c)
}
final public class Lexer {
......
// Copyright (c) 2016 Anarchy Tools Contributors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Foundation
//SR-138
extension String {
var toNSString: NSString {
#if os(Linux)
return self.bridge()
#elseif os(OSX)
return (self as NSString)
#endif
}
}
extension NSString {
var toString: String {
#if os(Linux)
return self.bridge()
#elseif os(OSX)
return (self as String)
#endif
}
}
//these parts of the Swift 3 API changes are not yet implemented on Linux
#if os(Linux)
extension String {