Skip to content

Commit

Permalink
Squashed commit of the following:
Browse files Browse the repository at this point in the history
commit bb02e01
Author: takeshi-1000 <stubgurssy@gmail.com>
Date:   Thu Dec 8 05:15:58 2022 +0900

    Fixed logic related to order of elements in localization directory Path array

commit bad37c9
Author: takeshi-1000 <stubgurssy@gmail.com>
Date:   Thu Dec 8 05:09:44 2022 +0900

    Revert "Fixed some logic in PBXVariantGroup."

    This reverts commit ea402c8.

commit ea402c8
Author: takeshi-1000 <stubgurssy@gmail.com>
Date:   Wed Dec 7 09:23:02 2022 +0900

    Fixed some logic in PBXVariantGroup.
    Try to make the logic simpler so that an error does not occur under the Linux environment.

commit b9359fb
Author: takeshi-1000 <stubgurssy@gmail.com>
Date:   Tue Dec 6 19:00:20 2022 +0900

    fix fixtures test

commit ca25eca
Author: takeshi-1000 <stubgurssy@gmail.com>
Date:   Tue Dec 6 12:33:23 2022 +0900

    fix compilation error in ci enviroment

commit a40341f
Author: takeshi-1000 <stubgurssy@gmail.com>
Date:   Mon Dec 5 21:05:49 2022 +0900

    add test

commit cb28c35
Author: takeshi-1000 <stubgurssy@gmail.com>
Date:   Mon Dec 5 21:05:41 2022 +0900

    update SourceGenerator, PBXProjGenerator, SourceType

    ## SourceGenerator
    - adapt SourceGenerator to TargetSourceFilterable
    - refactor variant group logic
    - add logic where you can add target membership to another target

    ## PBXProjGenerator
    - apply. new PBXProjGenerator

    ## SourceType
    - add new sourceType

commit 8a33b01
Author: takeshi-1000 <stubgurssy@gmail.com>
Date:   Mon Dec 5 21:05:08 2022 +0900

    add PBXVariantGroupGenerator, TargetSourceFilterable

commit e7f7537
Author: Mathieu Olivari <1377279+ma-oli@users.noreply.github.com>
Date:   Thu Nov 3 01:05:46 2022 -0700

    Fix includes related issues and improve their performances (yonaskolb#1275)

    * Fix recursive include path when relativePath is not set

    If relativePath is not set on a particular include, the first level of
    include will currently work, but starting at the second level of
    iteration, the computed include path will fail as relativePath will be
    appended over and over onto the filePath. We're fixing that recursion
    problem here and adding the corresponding tests to make sure it doesn't
    happen again.

    * Include projectRoot in include paths

    The projectRoot setting (when specified) is currently ignored when
    computing the include paths. We're fixing that in that commit.

    * Use memoization during recursive SpecFiles creation

    SpecFile objects are created by recursive through includes. On a large
    project with programatically generated SpecFile, it is not rare to have
    hundreds of SpecFiles, creating a large web of include dependencies.
    In such a case, it is not rare either for a particular SpecFile to be
    included by multiple other SpecFiles. When that happens, XcodeGen
    currently creates a SpecFile object every time a SpecFile gets included,
    which can lead to an exponential growth of includes.

    I have seen hundreds of files being turned into hundred of thousands of
    SpecFile object creations, which leads to an impractical XcodeGen run of
    tens of minutes.

    This change adds memoization during SpecFile recursion, in order to
    reuse the previously created SpecFiles, if available, instead of
    re-creating them.

    * Update CHANGELOG.md

    Add the following changes to the changelog:
    * b97bdc4 - Use memoization during recursive SpecFiles creation
    * a6b96ad - Include projectRoot in include paths
    * 557b074 - Fix recursive include path when relativePath is not set

commit 3e9fd04
Author: Roland <skofgar@users.noreply.github.com>
Date:   Wed Nov 2 07:42:22 2022 +0100

    allow multiple spec files to be provided to XcodeGen (yonaskolb#1270)

    * allow spec to be a comma separated list of specs instead of one

    * update readme and --spec command documentation

    * update Changelog

    * print project name

commit 87d7c7e
Author: Yonas Kolb <yonaskolb@users.noreply.github.com>
Date:   Sat Oct 1 20:50:18 2022 +1000

    Update CHANGELOG.md

commit 435c194
Author: SofteqDG <SofteqDG@users.noreply.github.com>
Date:   Sat Oct 1 11:23:09 2022 +0300

    Extend possible paths for SettingsPresets (yonaskolb#1135)

    * Search for presets in Bundle.main.resourcesPath dir (if exists)

commit ed5ec74
Author: Craig Siemens <siemens.craig@gmail.com>
Date:   Wed Sep 28 22:08:37 2022 -0600

    Added scheme generation for aggregate targets (yonaskolb#1250)

    * Updated SchemeGenerator to generate schemes for all projectTargets.

    * Added changelog entry

commit 6f33172
Author: Bobby Sudekum <1058624+bsudekum@users.noreply.github.com>
Date:   Fri Sep 9 01:43:39 2022 -0700

    Add enableGPUFrameCaptureMode to Scheme (yonaskolb#1251)

commit ebf70f1
Author: Yonas Kolb <yonaskolb@users.noreply.github.com>
Date:   Fri Aug 19 00:53:34 2022 +1000

    Update to 2.32.0

commit 594c67f
Author: freddi(Yuki Aki) <freddi-kit@users.noreply.github.com>
Date:   Fri Aug 12 15:21:43 2022 +0900

    Add `enable` option for `include` to enable optional including for addtional 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

commit e9295f1
Author: Steven Sheldon <steven@sasheldon.com>
Date:   Thu Aug 11 05:45:06 2022 -0700

    Fix profile action to not run frameworks (yonaskolb#1245)

    * Fix profile action to not run frameworks

    * Add PR number to changelog

    * Update CHANGELOG.md

    Co-authored-by: Yonas Kolb <yonaskolb@users.noreply.github.com>

commit ac525a4
Author: Shinolr <wyqbeta+github@gmail.com>
Date:   Tue Aug 9 22:32:33 2022 +0800

    remove redundant bracket (yonaskolb#1243)

commit 34f50d6
Author: Isaac Halvorson <hello@hisaac.net>
Date:   Mon Aug 1 17:27:14 2022 -0500

    Correct name of package in example yaml (yonaskolb#1240)

    Hey there, I just noticed that one of the example yaml snippets had the wrong package name specified.

commit ff552f3
Author: antonsergeev88 <antonsergeev88@gmail.com>
Date:   Sun Jul 31 11:33:20 2022 +0300

    Handle mlmodelc as a single unit (yonaskolb#1237)

    * Handle mlmodelc as a single unit

    * Add mlmodelc support in changelog

commit de2a537
Author: Yonas Kolb <yonaskolb@users.noreply.github.com>
Date:   Sun Jul 24 16:10:15 2022 +1000

    Update to 2.31.0

commit 24572da
Author: Aleksei Sapitskii <45671572+aleksproger@users.noreply.github.com>
Date:   Sun Jul 24 09:08:33 2022 +0300

    Added duplicate dependencies validation (yonaskolb#1234)

    **Reason**
     - More strict validation of added dependencies

    **Contents**
     - Added changelog entry
     - Added check for duplicates in validation stage
     - Added test

commit da8aad0
Author: matsuji <mtj0928@users.noreply.github.com>
Date:   Thu Jul 21 20:25:34 2022 +0900

    Add a new CopyFilesBuildPhase, "Embed ExtensionKit Extensions" (yonaskolb#1230)

    * Embed ExtensionKit Extensions

    * Fix explicitFileType for extensionKit

    * Update ChangeLog

    * Fix if statement structure

    * Add a new example extension to Tests/Fixtures/TestProject/

    * Update Tests/Fixtures/TestProject/Project.xcodeproj

    * Comment out example for extension kit extension in Tests/Fixtures/TestProject/

    * Update Tests/Fixtures/TestProject/Project.xcodeproj

commit c1d5c65
Author: Yonas Kolb <yonaskolb@users.noreply.github.com>
Date:   Sat Jul 16 16:57:26 2022 +1000

    Update to 2.30.0

commit c082bc0
Author: Aleksei Sapitskii <45671572+aleksproger@users.noreply.github.com>
Date:   Sat Jul 16 09:46:42 2022 +0300

    Fix XcodeGen building after XcodeProj update to 8.8.0 (yonaskolb#1228)

    * Fix XcodeGen building after XcodeProj update to 8.8.0

    **Reason**
    - XcodeProj has been updated and has API breaking changes

    **Content**
    - Added new enum case handling in `Linkage`
    - Renamed the enum case name for `XCWorkspaceDataFileRef.init`

    * add new product type to docs

    * update changelog

    Co-authored-by: Yonas Kolb <yonaskolb@users.noreply.github.com>

commit 19817f3
Author: Luca Bartoletti <luca.bartoletti@gmail.com>
Date:   Sat Jul 16 07:46:31 2022 +0100

    Fix `watchapp2-container` product name (yonaskolb#1219)

    The correct name is `application.watchapp2-container`
  • Loading branch information
mcfans committed Feb 22, 2023
1 parent b7a95fc commit b4e0f01
Show file tree
Hide file tree
Showing 62 changed files with 1,162 additions and 446 deletions.
199 changes: 190 additions & 9 deletions CHANGELOG.md

Large diffs are not rendered by default.

11 changes: 7 additions & 4 deletions 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 Expand Up @@ -274,6 +275,7 @@ This will provide default build settings for a certain product type. It can be a
- `application.messages`
- `application.watchapp`
- `application.watchapp2`
- `application.watchapp2-container`
- `app-extension`
- `app-extension.intents-service`
- `app-extension.messages`
Expand All @@ -282,14 +284,14 @@ This will provide default build settings for a certain product type. It can be a
- `bundle.ocunit-test`
- `bundle.ui-testing`
- `bundle.unit-test`
- `extensionkit-extension`
- `framework`
- `instruments-package`
- `library.dynamic`
- `library.static`
- `framework.static`
- `tool`
- `tv-app-extension`
- `watchapp2-container`
- `watchkit-extension`
- `watchkit2-extension`
- `xcode-extension`
Expand Down Expand Up @@ -731,7 +733,7 @@ This is used to override settings or run build scripts in specific targets

## Target Template

This is a template that can be referenced from a normal target using the `templates` property. The properties of this template are the same as a [Target](#target)].
This is a template that can be referenced from a normal target using the `templates` property. The properties of this template are the same as a [Target](#target).
Any instances of `${target_name}` within each template will be replaced by the final target name which references the template.
Any attributes defined within a targets `templateAttributes` will be used to replace any attribute references in the template using the syntax `${attribute_name}`.

Expand Down Expand Up @@ -806,6 +808,7 @@ The different actions share some properties:
- [ ] **preActions**: **[[Execution Action](#execution-action)]** - Scripts that are run *before* the action
- [ ] **postActions**: **[[Execution Action](#execution-action)]** - Scripts that are run *after* the action
- [ ] **environmentVariables**: **[[Environment Variable](#environment-variable)]** or **[String:String]** - `run`, `test` and `profile` actions can define the environment variables. When passing a dictionary, every key-value entry maps to a corresponding variable that is enabled.
- [ ] **enableGPUFrameCaptureMode**: **GPUFrameCaptureMode** - Property value set for `GPU Frame Capture`. Possible values are `autoEnabled`, `metal`, `openGL`, `disabled`. Default is `autoEnabled`.
- [ ] **disableMainThreadChecker**: **Bool** - `run` and `test` actions can define a boolean that indicates that this scheme should disable the Main Thread Checker. This defaults to false
- [ ] **stopOnEveryMainThreadCheckerIssue**: **Bool** - a boolean that indicates if this scheme should stop at every Main Thread Checker issue. This defaults to false
- [ ] **language**: **String** - `run` and `test` actions can define a language that is used for Application Language
Expand Down Expand Up @@ -1026,7 +1029,7 @@ packages:
Yams:
url: https://github.com/jpsim/Yams
from: 2.0.0
Yams:
Ink:
github: JohnSundell/Ink
from: 0.5.0
RxClient:
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
TOOL_NAME = XcodeGen
export EXECUTABLE_NAME = xcodegen
VERSION = 2.29.0
VERSION = 2.32.0

PREFIX = /usr/local
INSTALL_PATH = $(PREFIX)/bin/$(EXECUTABLE_NAME)
Expand Down
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@
"repositoryURL": "https://github.com/tuist/XcodeProj.git",
"state": {
"branch": null,
"revision": "c75c3acc25460195cfd203a04dde165395bf00e0",
"version": "8.7.1"
"revision": "b6de1bfe021b861c94e7c83821b595083f74b997",
"version": "8.8.0"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ let package = Package(
.package(url: "https://github.com/yonaskolb/JSONUtilities.git", from: "4.2.0"),
.package(url: "https://github.com/kylef/Spectre.git", from: "0.9.2"),
.package(url: "https://github.com/onevcat/Rainbow.git", from: "3.0.0"),
.package(url: "https://github.com/tuist/XcodeProj.git", from: "8.7.0"),
.package(url: "https://github.com/tuist/XcodeProj.git", from: "8.8.0"),
.package(url: "https://github.com/jakeheis/SwiftCLI.git", from: "6.0.3"),
.package(url: "https://github.com/mxcl/Version", from: "2.0.0"),
.package(url: "https://github.com/SwiftDocOrg/GraphViz.git", .exact("0.2.0")),
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ swift run xcodegen
Add the following to your Package.swift file's dependencies:

```swift
.package(url: "https://github.com/yonaskolb/XcodeGen.git", from: "2.29.0"),
.package(url: "https://github.com/yonaskolb/XcodeGen.git", from: "2.32.0"),
```

And then import wherever needed: `import XcodeGenKit`
Expand All @@ -130,7 +130,7 @@ This will look for a project spec in the current directory called `project.yml`

Options:

- **--spec**: An optional path to a `.yml` or `.json` project spec. Defaults to `project.yml`
- **--spec**: An optional path to a `.yml` or `.json` project spec. Defaults to `project.yml`. (It is also possible to link to multiple spec files by comma separating them. Note that all other flags will be the same.)
- **--project**: An optional path to a directory where the project will be generated. By default this is the directory the spec lives in.
- **--quiet**: Suppress informational and success messages.
- **--use-cache**: Used to prevent unnecessarily generating the project. If this is set, then a cache file will be written to when a project is generated. If `xcodegen` is later run but the spec and all the files it contains are the same, the project won't be generated.
Expand Down
2 changes: 2 additions & 0 deletions Sources/ProjectSpec/AggregateTarget.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import Foundation
import JSONUtilities
import XcodeProj

public struct AggregateTarget: ProjectTarget {
public var name: String
public var type: PBXProductType = .none
public var targets: [String]
public var settings: Settings
public var buildScripts: [BuildScript]
Expand Down
2 changes: 1 addition & 1 deletion Sources/ProjectSpec/Dependency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public struct Dependency: Equatable {
public static let `default` = dynamic
}

public enum DependencyType: Equatable {
public enum DependencyType: Hashable {
case target
case framework
case carthage(findFrameworks: Bool?, linkType: CarthageLinkType)
Expand Down
1 change: 1 addition & 0 deletions Sources/ProjectSpec/FileType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ extension FileType {
"intentdefinition": FileType(buildPhase: .sources),
"metal": FileType(buildPhase: .sources),
"mlmodel": FileType(buildPhase: .sources),
"mlmodelc": FileType(buildPhase: .resources),
"rcproject": FileType(buildPhase: .sources),
"iig": FileType(buildPhase: .sources),
"docc": FileType(buildPhase: .sources),
Expand Down
3 changes: 2 additions & 1 deletion Sources/ProjectSpec/Linkage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ extension Target {
.xcodeExtension,
.xpcService,
.systemExtension,
.driverExtension:
.driverExtension,
.extensionKitExtension:
return .none
case .framework, .xcFramework:
// Check the MACH_O_TYPE for "Static Framework"
Expand Down
9 changes: 8 additions & 1 deletion Sources/ProjectSpec/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,14 @@ extension Project: Equatable {
extension Project {

public init(path: Path) throws {
let spec = try SpecFile(path: path)
var cachedSpecFiles: [Path: SpecFile] = [:]
let spec = try SpecFile(filePath: path, basePath: path.parent(), cachedSpecFiles: &cachedSpecFiles)
try self.init(spec: spec)
}

public init(path: Path, basePath: Path) throws {
var cachedSpecFiles: [Path: SpecFile] = [:]
let spec = try SpecFile(filePath: path, basePath: basePath, cachedSpecFiles: &cachedSpecFiles)
try self.init(spec: spec)
}

Expand Down
2 changes: 2 additions & 0 deletions Sources/ProjectSpec/ProjectTarget.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import Foundation
import XcodeProj

public protocol ProjectTarget: BuildSettingsContainer {

var name: String { get }
var type: PBXProductType { get }
var buildScripts: [BuildScript] { get }
var scheme: TargetScheme? { get }
var attributes: [String: Any] { get }
Expand Down
42 changes: 42 additions & 0 deletions Sources/ProjectSpec/Scheme.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ public struct Scheme: Equatable {
public var preActions: [ExecutionAction]
public var postActions: [ExecutionAction]
public var environmentVariables: [XCScheme.EnvironmentVariable]
public var enableGPUFrameCaptureMode: XCScheme.LaunchAction.GPUFrameCaptureMode
public var disableMainThreadChecker: Bool
public var stopOnEveryMainThreadCheckerIssue: Bool
public var language: String?
Expand All @@ -150,6 +151,7 @@ public struct Scheme: Equatable {
preActions: [ExecutionAction] = [],
postActions: [ExecutionAction] = [],
environmentVariables: [XCScheme.EnvironmentVariable] = [],
enableGPUFrameCaptureMode: XCScheme.LaunchAction.GPUFrameCaptureMode = XCScheme.LaunchAction.defaultGPUFrameCaptureMode,
disableMainThreadChecker: Bool = disableMainThreadCheckerDefault,
stopOnEveryMainThreadCheckerIssue: Bool = stopOnEveryMainThreadCheckerIssueDefault,
language: String? = nil,
Expand All @@ -168,6 +170,7 @@ public struct Scheme: Equatable {
self.postActions = postActions
self.environmentVariables = environmentVariables
self.disableMainThreadChecker = disableMainThreadChecker
self.enableGPUFrameCaptureMode = enableGPUFrameCaptureMode
self.stopOnEveryMainThreadCheckerIssue = stopOnEveryMainThreadCheckerIssue
self.language = language
self.region = region
Expand Down Expand Up @@ -458,6 +461,11 @@ extension Scheme.Run: JSONObjectConvertible {
preActions = jsonDictionary.json(atKeyPath: "preActions") ?? []
postActions = jsonDictionary.json(atKeyPath: "postActions") ?? []
environmentVariables = try XCScheme.EnvironmentVariable.parseAll(jsonDictionary: jsonDictionary)
if let gpuFrameCaptureMode: String = jsonDictionary.json(atKeyPath: "enableGPUFrameCaptureMode") {
enableGPUFrameCaptureMode = XCScheme.LaunchAction.GPUFrameCaptureMode.fromJSONValue(gpuFrameCaptureMode)
} else {
enableGPUFrameCaptureMode = XCScheme.LaunchAction.defaultGPUFrameCaptureMode
}
disableMainThreadChecker = jsonDictionary.json(atKeyPath: "disableMainThreadChecker") ?? Scheme.Run.disableMainThreadCheckerDefault
stopOnEveryMainThreadCheckerIssue = jsonDictionary.json(atKeyPath: "stopOnEveryMainThreadCheckerIssue") ?? Scheme.Run.stopOnEveryMainThreadCheckerIssueDefault
language = jsonDictionary.json(atKeyPath: "language")
Expand Down Expand Up @@ -499,6 +507,10 @@ extension Scheme.Run: JSONEncodable {
"macroExpansion": macroExpansion
]

if enableGPUFrameCaptureMode != XCScheme.LaunchAction.defaultGPUFrameCaptureMode {
dict["enableGPUFrameCaptureMode"] = enableGPUFrameCaptureMode.toJSONValue()
}

if disableMainThreadChecker != Scheme.Run.disableMainThreadCheckerDefault {
dict["disableMainThreadChecker"] = disableMainThreadChecker
}
Expand Down Expand Up @@ -916,3 +928,33 @@ extension XCScheme.EnvironmentVariable: JSONEncodable {
return dict
}
}

extension XCScheme.LaunchAction.GPUFrameCaptureMode: JSONEncodable {
public func toJSONValue() -> Any {
switch self {
case .autoEnabled:
return "autoEnabled"
case .metal:
return "metal"
case .openGL:
return "openGL"
case .disabled:
return "disabled"
}
}

static func fromJSONValue(_ string: String) -> XCScheme.LaunchAction.GPUFrameCaptureMode {
switch string {
case "autoEnabled":
return .autoEnabled
case "metal":
return .metal
case "openGL":
return .openGL
case "disabled":
return .disabled
default:
fatalError("Invalid enableGPUFrameCaptureMode value. Valid values are: autoEnabled, metal, openGL, disabled")
}
}
}
1 change: 1 addition & 0 deletions Sources/ProjectSpec/SourceType.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ public enum SourceType: String {
case group
case file
case folder
case variantGroup
}
63 changes: 42 additions & 21 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, cachedSpecFiles: inout [Path: SpecFile], variables: [String: String] = [:]) throws {
try self.init(filePath: path, basePath: path.parent(), cachedSpecFiles: &cachedSpecFiles, variables: variables)
}

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

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

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

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

public init(filePath: Path, basePath: Path, cachedSpecFiles: inout [Path: SpecFile], variables: [String: String] = [:], relativePath: Path = "") throws {
let jsonDictionary = try SpecFile.loadDictionary(path: filePath).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
if let specFile = cachedSpecFiles[filePath] {
return specFile
} else {
return try SpecFile(include: include, basePath: basePath, relativePath: relativePath, cachedSpecFiles: &cachedSpecFiles, variables: variables)
}
}

self.init(filePath: filePath, jsonDictionary: jsonDictionary, basePath: basePath, relativePath: relativePath, subSpecs: subSpecs)
cachedSpecFiles[filePath] = self
}

static func loadDictionary(path: Path) throws -> JSONDictionary {
Expand All @@ -85,12 +99,13 @@ public struct SpecFile {
}
}

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

private func resolvedDictionaryWithUniqueTargets() -> JSONDictionary {
let resolvedSpec = resolvingPaths()
var cachedSpecFiles: [Path: SpecFile] = [:]
let resolvedSpec = resolvingPaths(cachedSpecFiles: &cachedSpecFiles)

var value = Set<String>()
return resolvedSpec.mergedDictionary(set: &value)
Expand All @@ -108,19 +123,25 @@ public struct SpecFile {
.reduce([:]) { $1.merged(onto: $0) })
}

func resolvingPaths(relativeTo basePath: Path = Path()) -> SpecFile {
func resolvingPaths(cachedSpecFiles: inout [Path: SpecFile], relativeTo basePath: Path = Path()) -> SpecFile {
if let cachedSpecFile = cachedSpecFiles[filePath] {
return cachedSpecFile
}

let relativePath = (basePath + self.relativePath).normalize()
guard relativePath != Path() else {
return self
}

let jsonDictionary = Project.pathProperties.resolvingPaths(in: self.jsonDictionary, relativeTo: relativePath)
return SpecFile(
let specFile = SpecFile(
filePath: filePath,
jsonDictionary: jsonDictionary,
relativePath: self.relativePath,
subSpecs: subSpecs.map { $0.resolvingPaths(relativeTo: relativePath) }
subSpecs: subSpecs.map { $0.resolvingPaths(cachedSpecFiles: &cachedSpecFiles, relativeTo: relativePath) }
)
cachedSpecFiles[filePath] = specFile
return specFile
}
}

Expand Down
Loading

0 comments on commit b4e0f01

Please sign in to comment.