From 985562484a7c984df4b1862e07dee835e5e0cd50 Mon Sep 17 00:00:00 2001 From: Wolfgang Lutz Date: Sun, 26 May 2024 11:39:42 +0200 Subject: [PATCH 1/4] Add Glob support for dictionary includes This change enables the use of Glob expressions (e.g. Sources/*/Package.yml) when including a yml file: ``` include: - path: Sources/*/Package.yml - path: Sources/*/Tests.yml - path: Sources/*/UITests.yml ``` --- Sources/ProjectSpec/SpecFile.swift | 49 ++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/Sources/ProjectSpec/SpecFile.swift b/Sources/ProjectSpec/SpecFile.swift index 18ea15628..a35f630e3 100644 --- a/Sources/ProjectSpec/SpecFile.swift +++ b/Sources/ProjectSpec/SpecFile.swift @@ -1,6 +1,7 @@ import Foundation import JSONUtilities import PathKit +import XcodeGenCore import Yams public struct SpecFile { @@ -26,22 +27,50 @@ public struct SpecFile { static let defaultEnable = true init?(any: Any) { - if let string = any as? String { - path = Path(string) - relativePaths = Include.defaultRelativePaths - enable = Include.defaultEnable + if let path = any as? String { + self.init( + path: Path(path), + relativePaths: Include.defaultRelativePaths, + enable: Include.defaultEnable + ) } else if let dictionary = any as? JSONDictionary, let path = dictionary["path"] as? String { - self.path = Path(path) - relativePaths = Self.resolveBoolean(dictionary, key: "relativePaths") ?? Include.defaultRelativePaths - enable = Self.resolveBoolean(dictionary, key: "enable") ?? Include.defaultEnable + self.init( + path: Path(path), + dictionary: dictionary + ) } else { return nil } } + + private init(path: Path, relativePaths: Bool, enable: Bool) { + self.path = path + self.relativePaths = relativePaths + self.enable = enable + } + + private init?(path: Path, dictionary: JSONDictionary) { + self.path = path + relativePaths = Self.resolveBoolean(dictionary, key: "relativePaths") ?? Include.defaultRelativePaths + enable = Self.resolveBoolean(dictionary, key: "enable") ?? Include.defaultEnable + } + + private static func includes(from array: [Any], basePath: Path) -> [Include] { + array.flatMap { entry -> [Include] in + if let string = entry as? String, let include = Include(any: string) { + [include] + } else if let dictionary = entry as? JSONDictionary, let path = dictionary["path"] as? String { + Glob(pattern: (basePath + Path(path)).normalize().string) + .compactMap { Include(path: Path($0), dictionary: dictionary) } + } else { + [] + } + } + } - static func parse(json: Any?) -> [Include] { + static func parse(json: Any?, basePath: Path) -> [Include] { if let array = json as? [Any] { - return array.compactMap(Include.init) + return includes(from: array, basePath: basePath) } else if let object = json, let include = Include(any: object) { return [include] } else { @@ -92,7 +121,7 @@ public struct SpecFile { let jsonDictionary = try SpecFile.loadDictionary(path: path).expand(variables: variables) - let includes = Include.parse(json: jsonDictionary["include"]) + let includes = Include.parse(json: jsonDictionary["include"], basePath: basePath) let subSpecs: [SpecFile] = try includes .filter(\.enable) .map { include in From 14e4455e2f15a8c1770997084dd776ffdcae80de Mon Sep 17 00:00:00 2001 From: Wolfgang Lutz Date: Sun, 26 May 2024 11:47:01 +0200 Subject: [PATCH 2/4] add return for older xcode/swift versions --- Sources/ProjectSpec/SpecFile.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/ProjectSpec/SpecFile.swift b/Sources/ProjectSpec/SpecFile.swift index a35f630e3..7a67da87c 100644 --- a/Sources/ProjectSpec/SpecFile.swift +++ b/Sources/ProjectSpec/SpecFile.swift @@ -58,12 +58,12 @@ public struct SpecFile { private static func includes(from array: [Any], basePath: Path) -> [Include] { array.flatMap { entry -> [Include] in if let string = entry as? String, let include = Include(any: string) { - [include] + return [include] } else if let dictionary = entry as? JSONDictionary, let path = dictionary["path"] as? String { - Glob(pattern: (basePath + Path(path)).normalize().string) + return Glob(pattern: (basePath + Path(path)).normalize().string) .compactMap { Include(path: Path($0), dictionary: dictionary) } } else { - [] + return [] } } } From 2c59b4e4f648e9a177224bb1e818943af74cb77c Mon Sep 17 00:00:00 2001 From: Wolfgang Lutz Date: Thu, 11 Jul 2024 17:19:06 +0200 Subject: [PATCH 3/4] Add Basic Test --- Tests/Fixtures/glob_include/glob_include_sut.yml | 3 +++ Tests/Fixtures/glob_include/includes/a_yaml.yml | 4 ++++ Tests/Fixtures/glob_include/includes/b_yaml.yml | 2 ++ Tests/ProjectSpecTests/SpecLoadingTests.swift | 11 +++++++++++ 4 files changed, 20 insertions(+) create mode 100644 Tests/Fixtures/glob_include/glob_include_sut.yml create mode 100644 Tests/Fixtures/glob_include/includes/a_yaml.yml create mode 100644 Tests/Fixtures/glob_include/includes/b_yaml.yml diff --git a/Tests/Fixtures/glob_include/glob_include_sut.yml b/Tests/Fixtures/glob_include/glob_include_sut.yml new file mode 100644 index 000000000..ce228f2f0 --- /dev/null +++ b/Tests/Fixtures/glob_include/glob_include_sut.yml @@ -0,0 +1,3 @@ +include: + - path: "*/*.yml" +name: GlobImportDependent \ No newline at end of file diff --git a/Tests/Fixtures/glob_include/includes/a_yaml.yml b/Tests/Fixtures/glob_include/includes/a_yaml.yml new file mode 100644 index 000000000..7bc4f2324 --- /dev/null +++ b/Tests/Fixtures/glob_include/includes/a_yaml.yml @@ -0,0 +1,4 @@ +name: DuplicatedImportRoot +fileGroups: + - First + - Second \ No newline at end of file diff --git a/Tests/Fixtures/glob_include/includes/b_yaml.yml b/Tests/Fixtures/glob_include/includes/b_yaml.yml new file mode 100644 index 000000000..6951d122e --- /dev/null +++ b/Tests/Fixtures/glob_include/includes/b_yaml.yml @@ -0,0 +1,2 @@ +fileGroups: + - Third \ No newline at end of file diff --git a/Tests/ProjectSpecTests/SpecLoadingTests.swift b/Tests/ProjectSpecTests/SpecLoadingTests.swift index 6a81c0907..2d4050f9a 100644 --- a/Tests/ProjectSpecTests/SpecLoadingTests.swift +++ b/Tests/ProjectSpecTests/SpecLoadingTests.swift @@ -25,6 +25,17 @@ class SpecLoadingTests: XCTestCase { } } + func testSpecLoaderGlobImports() { + describe { + $0.it("includes files via glob") { + let path = fixturePath + "glob_include/glob_include_sut.yml" + let project = try loadSpec(path: path) + + try expect(project.fileGroups) == ["First", "Second", "Third"] + } + } + } + func testSpecLoader() { describe { $0.it("merges includes") { From 71b3be13f02785bb06992cc84e478f89d3ae2a12 Mon Sep 17 00:00:00 2001 From: Wolfgang Lutz Date: Thu, 11 Jul 2024 19:00:03 +0200 Subject: [PATCH 4/4] implement string support for globs --- Sources/ProjectSpec/SpecFile.swift | 12 +++++++++++- .../glob_include/glob_include_sut_string.yml | 2 ++ Tests/ProjectSpecTests/SpecLoadingTests.swift | 11 +++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 Tests/Fixtures/glob_include/glob_include_sut_string.yml diff --git a/Sources/ProjectSpec/SpecFile.swift b/Sources/ProjectSpec/SpecFile.swift index 7a67da87c..582165508 100644 --- a/Sources/ProjectSpec/SpecFile.swift +++ b/Sources/ProjectSpec/SpecFile.swift @@ -55,6 +55,14 @@ public struct SpecFile { enable = Self.resolveBoolean(dictionary, key: "enable") ?? Include.defaultEnable } + private func replacingPath(with newPath: Path) -> Include { + Include( + path: newPath, + relativePaths: relativePaths, + enable: enable + ) + } + private static func includes(from array: [Any], basePath: Path) -> [Include] { array.flatMap { entry -> [Include] in if let string = entry as? String, let include = Include(any: string) { @@ -72,7 +80,9 @@ public struct SpecFile { if let array = json as? [Any] { return includes(from: array, basePath: basePath) } else if let object = json, let include = Include(any: object) { - return [include] + return Glob(pattern: (basePath + include.path.normalize()).string) + .compactMap { try? Path($0).relativePath(from: basePath) } + .compactMap { include.replacingPath(with: $0) } } else { return [] } diff --git a/Tests/Fixtures/glob_include/glob_include_sut_string.yml b/Tests/Fixtures/glob_include/glob_include_sut_string.yml new file mode 100644 index 000000000..f5dcffda4 --- /dev/null +++ b/Tests/Fixtures/glob_include/glob_include_sut_string.yml @@ -0,0 +1,2 @@ +include: "*/*.yml" +name: GlobImportDependent \ No newline at end of file diff --git a/Tests/ProjectSpecTests/SpecLoadingTests.swift b/Tests/ProjectSpecTests/SpecLoadingTests.swift index 2d4050f9a..cb1e3bedb 100644 --- a/Tests/ProjectSpecTests/SpecLoadingTests.swift +++ b/Tests/ProjectSpecTests/SpecLoadingTests.swift @@ -35,6 +35,17 @@ class SpecLoadingTests: XCTestCase { } } } + + func testSpecLoaderGlobImportsString() { + describe { + $0.it("includes files via glob") { + let path = fixturePath + "glob_include/glob_include_sut_string.yml" + let project = try loadSpec(path: path) + + try expect(project.fileGroups) == ["First", "Second", "Third"] + } + } + } func testSpecLoader() { describe {