From 2601d397929139c7a839354477af983454e209be Mon Sep 17 00:00:00 2001 From: Elliott Williams Date: Mon, 23 Nov 2020 16:28:41 -0800 Subject: [PATCH] Support Linux by upgrading XcodeProj and Spectre (#988) * Bump XcodeProj and Spectre * Add LinuxMain.swift * Linux test fixups * Add CI job for ubuntu-latest * Use URLs in glob logic to avoid Linux/Mac foundation inconsistencies * fatalError when --enable-test-discovery is not used * Update fixtures They changed because of a bugfix in XcodeProj: https://github.com/tuist/XcodeProj/pull/563 * Update CHANGELOG.md --- .github/workflows/ci.yml | 7 ++++ CHANGELOG.md | 1 + Package.resolved | 33 +++++++----------- Package.swift | 4 +-- Sources/Core/Glob.swift | 34 +++++++++++-------- Sources/ProjectSpec/Linkage.swift | 1 + Sources/XcodeGenKit/SchemeGenerator.swift | 2 +- Tests/CoreTests/GlobTests.swift | 2 +- .../AnotherProject.xcodeproj/project.pbxproj | 2 +- .../Project.xcodeproj/project.pbxproj | 6 ++-- Tests/LinuxMain.swift | 3 ++ Tests/ProjectSpecTests/SpecLoadingTests.swift | 2 +- 12 files changed, 53 insertions(+), 44 deletions(-) create mode 100644 Tests/LinuxMain.swift diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bcb9f46e..c396e348 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,3 +32,10 @@ jobs: run: scripts/diff-fixtures.sh - name: Build fixtures run: scripts/build-fixtures.sh + run-linux: + runs-on: ubuntu-latest + name: Linux + steps: + - uses: actions/checkout@master + - name: Build and run tests + run: swift test --enable-test-discovery diff --git a/CHANGELOG.md b/CHANGELOG.md index 708192f4..fc5565d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Next Version #### Added +- Support for building and running on Linux platforms. Tested for compatibility with Swift 5.3+ and Ubuntu 18.04. [#988](https://github.com/yonaskolb/XcodeGen/pull/988) @elliottwilliams - Add `useBaseInternationalization` to Project Spec Options to opt out of Base Internationalization. [#961](https://github.com/yonaskolb/XcodeGen/pull/961) @liamnichols #### Fixed diff --git a/Package.resolved b/Package.resolved index 672c8610..e42136a4 100644 --- a/Package.resolved +++ b/Package.resolved @@ -6,8 +6,8 @@ "repositoryURL": "https://github.com/tadija/AEXML", "state": { "branch": null, - "revision": "e4d517844dd03dac557e35d77a8e9ab438de91a6", - "version": "4.4.0" + "revision": "8623e73b193386909566a9ca20203e33a09af142", + "version": "4.5.0" } }, { @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/SwiftDocOrg/GraphViz.git", "state": { "branch": null, - "revision": "08e0cddd013fa2272379d27ec3e0093db51f34fb", - "version": "0.1.0" + "revision": "c4746cb3ff6f5e7c5d5540c40b98555521c3ee43", + "version": "0.1.3" } }, { @@ -42,8 +42,8 @@ "repositoryURL": "https://github.com/onevcat/Rainbow.git", "state": { "branch": null, - "revision": "9c52c1952e9b2305d4507cf473392ac2d7c9b155", - "version": "3.1.5" + "revision": "626c3d4b6b55354b4af3aa309f998fae9b31a3d9", + "version": "3.2.0" } }, { @@ -51,8 +51,8 @@ "repositoryURL": "https://github.com/kylef/Spectre.git", "state": { "branch": null, - "revision": "f14ff47f45642aa5703900980b014c2e9394b6e5", - "version": "0.9.0" + "revision": "f79d4ecbf8bc4e1579fbd86c3e1d652fb6876c53", + "version": "0.9.2" } }, { @@ -60,8 +60,8 @@ "repositoryURL": "https://github.com/jakeheis/SwiftCLI.git", "state": { "branch": null, - "revision": "c72c4564f8c0a24700a59824880536aca45a4cae", - "version": "6.0.1" + "revision": "2816678bcc37f4833d32abeddbdf5e757fa891d8", + "version": "6.0.2" } }, { @@ -78,17 +78,8 @@ "repositoryURL": "https://github.com/tuist/XcodeProj.git", "state": { "branch": null, - "revision": "545bfa746b6eb4ea0ad8d3a12c6590445392bb50", - "version": "7.13.0" - } - }, - { - "package": "XcodeProjCExt", - "repositoryURL": "https://github.com/tuist/XcodeProjCExt", - "state": { - "branch": null, - "revision": "21a510c225ff2bc83d5920a21d902af4b1e7e218", - "version": "0.1.0" + "revision": "82bf5efcaa27e94ed8c761c1eb3e397b6dea82b9", + "version": "7.18.0" } }, { diff --git a/Package.swift b/Package.swift index baf31373..3d5c5b40 100644 --- a/Package.swift +++ b/Package.swift @@ -14,9 +14,9 @@ let package = Package( .package(url: "https://github.com/kylef/PathKit.git", from: "1.0.0"), .package(url: "https://github.com/jpsim/Yams.git", from: "4.0.0"), .package(url: "https://github.com/yonaskolb/JSONUtilities.git", from: "4.2.0"), - .package(url: "https://github.com/kylef/Spectre.git", from: "0.9.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", .exact("7.13.0")), + .package(url: "https://github.com/tuist/XcodeProj.git", from: "7.18.0"), .package(url: "https://github.com/jakeheis/SwiftCLI.git", from: "6.0.0"), .package(url: "https://github.com/mxcl/Version", from: "2.0.0"), .package(url: "https://github.com/SwiftDocOrg/GraphViz.git", from: "0.1.0"), diff --git a/Sources/Core/Glob.swift b/Sources/Core/Glob.swift index 9eccc61d..b263cf5d 100644 --- a/Sources/Core/Glob.swift +++ b/Sources/Core/Glob.swift @@ -136,7 +136,7 @@ public class Glob: Collection { let firstPart = parts.removeFirst() var lastPart = parts.joined(separator: "**") - var directories: [String] + var directories: [URL] if FileManager.default.fileExists(atPath: firstPart) { do { @@ -151,7 +151,7 @@ public class Glob: Collection { if behavior.includesFilesFromRootOfGlobstar { // Check the base directory for the glob star as well. - directories.insert(firstPart, at: 0) + directories.insert(URL(fileURLWithPath: firstPart), at: 0) // Include the globstar root directory ("dir/") in a pattern like "dir/**" or "dir/**/" if lastPart.isEmpty { @@ -163,29 +163,30 @@ public class Glob: Collection { lastPart = "*" } for directory in directories { - let partiallyResolvedPattern = NSString(string: directory).appendingPathComponent(lastPart) - results.append(contentsOf: expandGlobstar(pattern: partiallyResolvedPattern)) + let partiallyResolvedPattern = directory.appendingPathComponent(lastPart) + let standardizedPattern = (partiallyResolvedPattern.relativePath as NSString).standardizingPath + results.append(contentsOf: expandGlobstar(pattern: standardizedPattern)) } return results } - private func exploreDirectories(path: String) throws -> [String] { + private func exploreDirectories(path: String) throws -> [URL] { try FileManager.default.contentsOfDirectory(atPath: path) - .compactMap { subpath -> [String]? in + .compactMap { subpath -> [URL]? in if blacklistedDirectories.contains(subpath) { return nil } - let firstLevelPath = NSString(string: path).appendingPathComponent(subpath) - guard isDirectory(path: firstLevelPath) else { + let firstLevel = URL(fileURLWithPath: path).appendingPathComponent(subpath, isDirectory: true) + guard isDirectory(path: firstLevel.path) else { return nil } - var subDirs: [String] = try FileManager.default.subpathsOfDirectory(atPath: firstLevelPath) - .compactMap { subpath -> String? in - let fullPath = NSString(string: firstLevelPath).appendingPathComponent(subpath) - return isDirectory(path: fullPath) ? fullPath : nil + var subDirs: [URL] = try FileManager.default.subpathsOfDirectory(atPath: firstLevel.path) + .compactMap { subpath -> URL? in + let full = firstLevel.appendingPathComponent(subpath, isDirectory: true) + return isDirectory(path: full.path) ? full : nil } - subDirs.append(firstLevelPath) + subDirs.append(firstLevel) return subDirs } .joined() @@ -211,7 +212,12 @@ public class Glob: Collection { private func populateFiles(gt: glob_t, includeFiles: Bool) { let includeDirectories = behavior.includesDirectoriesInResults - for i in 0.. String { - var tmpDirTmpl = "/tmp/glob-test.XXXXX".cString(using: .utf8)! + var tmpDirTmpl = "/tmp/glob-test.XXXXXX".cString(using: .utf8)! return String(validatingUTF8: mkdtemp(&tmpDirTmpl))! } diff --git a/Tests/Fixtures/TestProject/AnotherProject/AnotherProject.xcodeproj/project.pbxproj b/Tests/Fixtures/TestProject/AnotherProject/AnotherProject.xcodeproj/project.pbxproj index e4ae5449..9ca47777 100644 --- a/Tests/Fixtures/TestProject/AnotherProject/AnotherProject.xcodeproj/project.pbxproj +++ b/Tests/Fixtures/TestProject/AnotherProject/AnotherProject.xcodeproj/project.pbxproj @@ -7,7 +7,7 @@ objects = { /* Begin PBXFileReference section */ - 6023D61BF2C57E6AE09CE7A3 /* BundleX.bundle */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "wrapper.plug-in"; path = BundleX.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 6023D61BF2C57E6AE09CE7A3 /* BundleX.bundle */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = BundleX.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 60D6679FB526839EAFEA2EEE /* config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = config.xcconfig; sourceTree = ""; }; D6340FC7DEBC81E0127BAFD6 /* ExternalTarget.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ExternalTarget.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ diff --git a/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj b/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj index 0a3bace0..185a1781 100644 --- a/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj +++ b/Tests/Fixtures/TestProject/Project.xcodeproj/project.pbxproj @@ -617,7 +617,7 @@ 3FC04772130400920D68A167 /* App_Clip_Tests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = App_Clip_Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 40863AE6202CFCD0529D8438 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 41FC82ED1C4C3B7B3D7B2FB7 /* Framework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Framework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 45C12576F5AA694DD0CE2132 /* BundleX.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = BundleX.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 45C12576F5AA694DD0CE2132 /* BundleX.bundle */ = {isa = PBXFileReference; lastKnownFileType = wrapper.cfbundle; path = BundleX.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 469B630D28015F0EDC456F6B /* libStaticLibrary_ObjC.a */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = archive.ar; path = libStaticLibrary_ObjC.a; sourceTree = BUILT_PRODUCTS_DIR; }; 46DD8F9AAC104BDB63793625 /* libStaticLibrary_ObjC.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libStaticLibrary_ObjC.a; sourceTree = BUILT_PRODUCTS_DIR; }; 4BF4D16042A80576D259160C /* Model 3.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Model 3.xcdatamodel"; sourceTree = ""; }; @@ -636,7 +636,7 @@ 70A8E15C81E454DC950C59F0 /* SomeXPCService.xpc */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.xpc-service"; path = SomeXPCService.xpc; sourceTree = ""; }; 72A14C887EF7E9C8CBE914AC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 77C0C341F1865224E0596086 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; - 7B5068D64404C61A67A18458 /* MyBundle.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = MyBundle.bundle; sourceTree = ""; }; + 7B5068D64404C61A67A18458 /* MyBundle.bundle */ = {isa = PBXFileReference; lastKnownFileType = wrapper.cfbundle; path = MyBundle.bundle; sourceTree = ""; }; 7C176A8297AC2F5207352BA8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; 7C7EC00B53FF878007F6ECAB /* App_Clip_UITests.xctest */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.cfbundle; path = App_Clip_UITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 7D67F1C1BFBACE101DE7DB51 /* Framework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Framework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -648,7 +648,7 @@ 86169DEEDEAF09AB89C8A31D /* libStaticLibrary_ObjC.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libStaticLibrary_ObjC.a; sourceTree = BUILT_PRODUCTS_DIR; }; 87DF9DCA8399E3214A7E27CF /* TestProjectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestProjectTests.swift; sourceTree = ""; }; 8A9274BE42A03DC5DA1FAD04 /* Framework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Framework.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 8AF20308873AEEEC4D8C45D1 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; + 8AF20308873AEEEC4D8C45D1 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = wrapper.cfbundle; path = Settings.bundle; sourceTree = ""; }; 8CAF6C55B555E3E1352645B6 /* ExtensionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionDelegate.swift; sourceTree = ""; }; 8CB86294FB939FE6E90932E1 /* libStaticLibrary_Swift.a */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = archive.ar; path = libStaticLibrary_Swift.a; sourceTree = BUILT_PRODUCTS_DIR; }; 8D88C6BF7355702B74396791 /* TestProjectUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestProjectUITests.swift; sourceTree = ""; }; diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift new file mode 100644 index 00000000..711a949e --- /dev/null +++ b/Tests/LinuxMain.swift @@ -0,0 +1,3 @@ +// LinuxMain.swift +fatalError("Run the tests with `swift test --enable-test-discovery`.") + diff --git a/Tests/ProjectSpecTests/SpecLoadingTests.swift b/Tests/ProjectSpecTests/SpecLoadingTests.swift index 58617b9b..3a7b5ec5 100644 --- a/Tests/ProjectSpecTests/SpecLoadingTests.swift +++ b/Tests/ProjectSpecTests/SpecLoadingTests.swift @@ -202,7 +202,7 @@ class SpecLoadingTests: XCTestCase { throw failure("\(key): \(parsedValue) does not equal \(expectedValue)") } } - if !(dictionary as NSDictionary).isEqual(expectedDictionary) { + if !(dictionary as NSDictionary).isEqual(expectedDictionary as NSDictionary) { throw failure("parsed yaml types don't match:\n\nParsed:\n\t\(dictionary.map { "\($0.key): \($0.value)" }.joined(separator: "\n\t"))\nExpected:\n\t\(expectedDictionary.map { "\($0.key): \($0.value)" }.joined(separator: "\n\t"))") } }