Skip to content

Commit

Permalink
Add enable option for include to enable optional including for ad…
Browse files Browse the repository at this point in the history
…dtional spec (yonaskolb#1242)

* add new option enable for include of spec

* fix to see the environment variable when parsing include

* add test for include with environment variable

* fix how to parse boolean value

* add spec about enable for include

* add Change Log

* fix the number of PR in changelog

* fix include test to make more clear

* fix test to focus enable option more

* fix english error

* fix to expand variable only one time

* add new test case by setting environment object as NO
  • Loading branch information
freddi-kit authored Aug 12, 2022
1 parent e9295f1 commit 594c67f
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 22 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
### Added

- Add support for `mlmodelc` files #1236 @antonsergeev88
- Add `enable` option for `include` #1242 @freddi-kit

### Fixed
- Fix checking environment variable in `include` #1242 @freddi-kit

### Fixed

Expand Down
3 changes: 2 additions & 1 deletion Docs/ProjectSpec.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,13 @@ An include can be provided via a string (the path) or an object of the form:

- [x] **path**: **String** - The path to the included file.
- [ ] **relativePaths**: **Bool** - Dictates whether the included spec specifies paths relative to itself (the default) or the root spec file.

- [ ] **enable**: **Bool** - Dictates whether the specified spec should be included or not. You can also specify it by environment variable.
```yaml
include:
- includedFile.yml
- path: path/to/includedFile.yml
relativePaths: false
enable: ${INCLUDE_ADDITIONAL_YAML}
```
By default specs are merged additively. That is for every value:
Expand Down
38 changes: 24 additions & 14 deletions Sources/ProjectSpec/SpecFile.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Foundation
import JSONUtilities
import PathKit
import Yams

public struct SpecFile {
public let basePath: Path
Expand All @@ -13,17 +14,20 @@ public struct SpecFile {
fileprivate struct Include {
let path: Path
let relativePaths: Bool
let enable: Bool

static let defaultRelativePaths = true
static let defaultEnable = true

init?(any: Any) {
if let string = any as? String {
path = Path(string)
relativePaths = Include.defaultRelativePaths
} else if let dictionary = any as? JSONDictionary,
let path = dictionary["path"] as? String {
enable = Include.defaultEnable
} else if let dictionary = any as? JSONDictionary, let path = dictionary["path"] as? String {
self.path = Path(path)
relativePaths = dictionary["relativePaths"] as? Bool ?? Include.defaultRelativePaths
relativePaths = Self.resolveBoolean(dictionary, key: "relativePaths") ?? Include.defaultRelativePaths
enable = Self.resolveBoolean(dictionary, key: "enable") ?? Include.defaultEnable
} else {
return nil
}
Expand All @@ -38,10 +42,14 @@ public struct SpecFile {
return []
}
}

private static func resolveBoolean(_ dictionary: [String: Any], key: String) -> Bool? {
dictionary[key] as? Bool ?? (dictionary[key] as? NSString)?.boolValue
}
}

public init(path: Path) throws {
try self.init(filePath: path, basePath: path.parent())
public init(path: Path, variables: [String: String] = [:]) throws {
try self.init(filePath: path, basePath: path.parent(), variables: variables)
}

public init(filePath: Path, jsonDictionary: JSONDictionary, basePath: Path = "", relativePath: Path = "", subSpecs: [SpecFile] = []) {
Expand All @@ -52,21 +60,23 @@ public struct SpecFile {
self.filePath = filePath
}

private init(include: Include, basePath: Path, relativePath: Path) throws {
private init(include: Include, basePath: Path, relativePath: Path, variables: [String: String]) throws {
let basePath = include.relativePaths ? (basePath + relativePath) : (basePath + relativePath + include.path.parent())
let relativePath = include.relativePaths ? include.path.parent() : Path()

try self.init(filePath: include.path, basePath: basePath, relativePath: relativePath)
try self.init(filePath: include.path, basePath: basePath, variables: variables, relativePath: relativePath)
}

private init(filePath: Path, basePath: Path, relativePath: Path = "") throws {
private init(filePath: Path, basePath: Path, variables: [String: String], relativePath: Path = "") throws {
let path = basePath + relativePath + filePath.lastComponent
let jsonDictionary = try SpecFile.loadDictionary(path: path)
let jsonDictionary = try SpecFile.loadDictionary(path: path).expand(variables: variables)

let includes = Include.parse(json: jsonDictionary["include"])
let subSpecs: [SpecFile] = try includes.map { include in
try SpecFile(include: include, basePath: basePath, relativePath: relativePath)
}
let subSpecs: [SpecFile] = try includes
.filter(\.enable)
.map { include in
try SpecFile(include: include, basePath: basePath, relativePath: relativePath, variables: variables)
}

self.init(filePath: filePath, jsonDictionary: jsonDictionary, basePath: basePath, relativePath: relativePath, subSpecs: subSpecs)
}
Expand All @@ -85,8 +95,8 @@ public struct SpecFile {
}
}

public func resolvedDictionary(variables: [String: String] = [:]) -> JSONDictionary {
resolvedDictionaryWithUniqueTargets().expand(variables: variables)
public func resolvedDictionary() -> JSONDictionary {
resolvedDictionaryWithUniqueTargets()
}

private func resolvedDictionaryWithUniqueTargets() -> JSONDictionary {
Expand Down
4 changes: 2 additions & 2 deletions Sources/ProjectSpec/SpecLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ public class SpecLoader {
}

public func loadProject(path: Path, projectRoot: Path? = nil, variables: [String: String] = [:]) throws -> Project {
let spec = try SpecFile(path: path)
let resolvedDictionary = spec.resolvedDictionary(variables: variables)
let spec = try SpecFile(path: path, variables: variables)
let resolvedDictionary = spec.resolvedDictionary()
let project = try Project(basePath: projectRoot ?? spec.basePath, jsonDictionary: resolvedDictionary)

self.project = project
Expand Down
11 changes: 10 additions & 1 deletion Tests/Fixtures/include_test.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
include: [included.yml]
include:
- included.yml
- path: included_addtional.yml
enable: ${INCLUDE_ADDTIONAL_YAML}
packages:
Yams:
url: https://github.com/jpsim/Yams
majorVersion: 2.0.0
name: NewName
settingGroups:
test:
Expand All @@ -19,3 +26,5 @@ targets:
name: IncludedTargetNew
platform: tvOS
sources:REPLACE: NewSource
dependencies:
- package: Yams
12 changes: 12 additions & 0 deletions Tests/Fixtures/included_addtional.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name: Included_Addtional
settingGroups:
test:
MY_SETTING5: ADDTIONAL
packages:
SwiftPM:
url: https://github.com/apple/swift-package-manager
branch: swift-5.0-branch
targets:
IncludedTarget:
dependencies:
- package: SwiftPM
4 changes: 2 additions & 2 deletions Tests/PerformanceTests/PerformanceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ class GeneratedPerformanceTests: XCTestCase {
try dumpYamlDictionary(project.toJSONDictionary(), path: specPath)

measure {
let spec = try! SpecFile(path: specPath)
_ = spec.resolvedDictionary(variables: ProcessInfo.processInfo.environment)
let spec = try! SpecFile(path: specPath, variables: ProcessInfo.processInfo.environment)
_ = spec.resolvedDictionary()
}
}

Expand Down
36 changes: 34 additions & 2 deletions Tests/ProjectSpecTests/SpecLoadingTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class SpecLoadingTests: XCTestCase {
describe {
$0.it("merges includes") {
let path = fixturePath + "include_test.yml"
let project = try loadSpec(path: path)
let project = try loadSpec(path: path, variables: [:])

try expect(project.name) == "NewName"
try expect(project.settingGroups) == [
Expand All @@ -38,7 +38,39 @@ class SpecLoadingTests: XCTestCase {
"toReplace": Settings(dictionary: ["MY_SETTING2": "VALUE2"]),
]
try expect(project.targets) == [
Target(name: "IncludedTargetNew", type: .application, platform: .tvOS, sources: ["NewSource"]),
Target(name: "IncludedTargetNew", type: .application, platform: .tvOS, sources: ["NewSource"], dependencies: [Dependency(type: .package(product: nil), reference: "Yams")]),
Target(name: "NewTarget", type: .application, platform: .iOS, sources: ["template", "target"]),
]
}

$0.it("merges includes with addtional one") {
let path = fixturePath + "include_test.yml"
let project = try loadSpec(path: path, variables: ["INCLUDE_ADDTIONAL_YAML": "YES"])

try expect(project.name) == "NewName"
try expect(project.settingGroups) == [
"test": Settings(dictionary: ["MY_SETTING1": "NEW VALUE", "MY_SETTING2": "VALUE2", "MY_SETTING3": "VALUE3", "MY_SETTING4": "${SETTING4}", "MY_SETTING5": "ADDTIONAL"]),
"new": Settings(dictionary: ["MY_SETTING": "VALUE"]),
"toReplace": Settings(dictionary: ["MY_SETTING2": "VALUE2"]),
]
try expect(project.targets) == [
Target(name: "IncludedTargetNew", type: .application, platform: .tvOS, sources: ["NewSource"], dependencies: [Dependency(type: .package(product: nil), reference: "SwiftPM"), Dependency(type: .package(product: nil), reference: "Yams")]),
Target(name: "NewTarget", type: .application, platform: .iOS, sources: ["template", "target"]),
]
}

$0.it("merges includes without addtional one by environemnt variable") {
let path = fixturePath + "include_test.yml"
let project = try loadSpec(path: path, variables: ["INCLUDE_ADDTIONAL_YAML": "NO"])

try expect(project.name) == "NewName"
try expect(project.settingGroups) == [
"test": Settings(dictionary: ["MY_SETTING1": "NEW VALUE", "MY_SETTING2": "VALUE2", "MY_SETTING3": "VALUE3", "MY_SETTING4": "${SETTING4}"]),
"new": Settings(dictionary: ["MY_SETTING": "VALUE"]),
"toReplace": Settings(dictionary: ["MY_SETTING2": "VALUE2"]),
]
try expect(project.targets) == [
Target(name: "IncludedTargetNew", type: .application, platform: .tvOS, sources: ["NewSource"], dependencies: [Dependency(type: .package(product: nil), reference: "Yams")]),
Target(name: "NewTarget", type: .application, platform: .iOS, sources: ["template", "target"]),
]
}
Expand Down

0 comments on commit 594c67f

Please sign in to comment.