From c4d09cd808b6693b6cac34f8e0aae4bcc8766ffd Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Fri, 28 Apr 2023 17:37:09 +0000 Subject: [PATCH] [Setup] Non Apple platforms (#13) This PR contains the work done to address the issue #12, with regards to provide basic support of non Apple platforms. To provide further details about the work done: - [x] flattened the folder structure, especially now that the idea to filter folders based on platform is being discarded; - [x] implemented precompiler processors to filter out platform-specific source code; - [x] updated the `Package` file to provide basic support for non-Apple platforms; - [x] added and also improved some targets to the `Makefile` file to smooth the current development workflows; - [x] updated the `.gitignore` file with references to the `.vscode` folder and the `.env` file; - [x] updated the Swift tools version to v5.7. Co-authored-by: Javier Cicchelli Reviewed-on: https://repo.rock-n-code.com/rock-n-code/swift-libs/pulls/13 --- .gitignore | 2 + Makefile | 87 ++++++++++ Package.swift | 164 ++++++++++-------- .../Classes/MockURLProtocol.swift | 2 + .../Use Cases/MakeURLRequestUseCase.swift | 2 + .../Routers/BaseNavigationRouter.swift | 2 + .../Routers/ModalNavigationRouter.swift | 2 + .../Routers/PushNavigationRouter.swift | 2 + .../iOS => }/Routers/WindowRouter.swift | 2 + Sources/Persistence/Classes/Fetcher.swift | 2 + Sources/Persistence/Protocols/Service.swift | 2 + .../MakeURLRequestUseCaseTests.swift | 2 + .../Protocols/CoordinatorTests.swift | 2 + .../iOS => }/Helpers/TestCoordinators.swift | 2 + .../Property Wrappers/DependencyTests.swift | 0 .../Services/DependencyServiceTests.swift | 0 .../{ => Cases}/Classes/FetcherTests.swift | 0 .../Extensions/URL+DevicesTests.swift | 0 Tests/Persistence/Helpers/TestEntity.swift | 29 ++++ .../Helpers/TestPersistenceService.swift | 1 + .../Model.xcdatamodel/contents | 2 +- 21 files changed, 232 insertions(+), 75 deletions(-) create mode 100644 Makefile rename Sources/Coordination/{Platform/iOS => }/Routers/BaseNavigationRouter.swift (99%) rename Sources/Coordination/{Platform/iOS => }/Routers/ModalNavigationRouter.swift (99%) rename Sources/Coordination/{Platform/iOS => }/Routers/PushNavigationRouter.swift (99%) rename Sources/Coordination/{Platform/iOS => }/Routers/WindowRouter.swift (98%) rename Tests/Communications/{ => Cases}/Use Cases/MakeURLRequestUseCaseTests.swift (98%) rename Tests/Coordination/{Platform/iOS => Cases}/Protocols/CoordinatorTests.swift (99%) rename Tests/Coordination/{Platform/iOS => }/Helpers/TestCoordinators.swift (98%) rename Tests/Dependencies/{ => Cases}/Property Wrappers/DependencyTests.swift (100%) rename Tests/Dependencies/{ => Cases}/Services/DependencyServiceTests.swift (100%) rename Tests/Persistence/{ => Cases}/Classes/FetcherTests.swift (100%) rename Tests/Persistence/{ => Cases}/Extensions/URL+DevicesTests.swift (100%) create mode 100644 Tests/Persistence/Helpers/TestEntity.swift rename Tests/Persistence/{Helpers => Resources}/TestModel.xcdatamodeld/Model.xcdatamodel/contents (88%) diff --git a/.gitignore b/.gitignore index 3b29812..9411668 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .DS_Store /.build +/.vscode /Packages /*.xcodeproj xcuserdata/ @@ -7,3 +8,4 @@ DerivedData/ .swiftpm/config/registries.json .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata .netrc +.env \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fe8c794 --- /dev/null +++ b/Makefile @@ -0,0 +1,87 @@ +# --- IMPORTS --- + +# Imports environment variables. +environment_vars ?= .env + +include $(environment_vars) +export $(shell sed 's/=.*//' $(environment_vars)) + +# --- ARGUMENTS --- + +override docker?=${CLI_USE_DOCKER} +override tag?=${DOCKER_IMAGE_TAG} +override platform?=${DOCKER_IMAGE_PLATFORM} +override config?=${SWIFT_BUILD_CONFIGURATION} +override clean?=${DOCKER_IMAGE_CLEAN} + +# --- DEPENDENCIES --- + +outdated: ## List the package dependencies that can be updated. + @swift package update --dry-run + +update: ## Update the package dependencies defined in the project. + @swift package update + +# --- DEVELOPMENT --- + +build: ## Build this package with Swift either locally or in a Docker image. +ifeq ($(docker),yes) + @-docker run \ + --rm \ + --volume ${PWD}:${DOCKER_VOLUME_TARGET} \ + --workdir ${DOCKER_VOLUME_TARGET} \ + --platform ${platform} \ + ${DOCKER_IMAGE_NAME}:${tag} \ + swift build --configuration ${config} + ifeq ($(clean),yes) + @docker rmi ${DOCKER_IMAGE_NAME}:${tag} + endif +else + @swift build --configuration ${config} +endif + +# --- TESTING --- + +test: ## Test this package with Swift either locally or in a Docker image. +ifeq ($(docker),yes) + @-docker run \ + --rm \ + --volume ${PWD}:${DOCKER_VOLUME_TARGET} \ + --workdir ${DOCKER_VOLUME_TARGET} \ + --platform ${platform} \ + ${DOCKER_IMAGE_NAME}:${tag} \ + swift test --configuration ${config} + ifeq ($(clean),yes) + @docker rmi ${DOCKER_IMAGE_NAME}:${tag} + endif +else + @swift test --configuration ${config} +endif + +# --- HOUSE-KEEPING --- + +clean: ## Clean the build artifacts of the package. + @swift package clean + +reset: ## Reset the build folder of the package. + @swift package reset + +flush-images: ## Flush all outstanding Swift docker images. + @docker images \ + --all | grep ${DOCKER_IMAGE_NAME} | awk '{print $$3}' | xargs docker rmi --force + +# --- MISCELLANEOUS --- + +xcode: ## Open this package in Xcode. + @open -a Xcode Package.swift + +# --- HELP --- + +# Outputs the documentation for each of the defined tasks when `help` is called. +# Reference: https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html +.PHONY: help + +help: ## Prints the written documentation for all the defined tasks. + @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) + +.DEFAULT_GOAL := help diff --git a/Package.swift b/Package.swift index 8d07528..f7c463c 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version: 5.5 +// swift-tools-version: 5.7 // // This source file is part of the SwiftLibs open source project // @@ -11,14 +11,86 @@ import PackageDescription -private var excludePlatforms: [String] = [.PlatformFolder.iOS] +// MARK: - Variables -#if os(iOS) -excludePlatforms = [] +private var targetsLibrary: [String] = [ + .Target.communications, + .Target.coordination, + .Target.core, + .Target.dependencies, +] + +private var targetsPackage: [Target] = [ + .target( + name: .Target.communications, + dependencies: [] + ), + .target( + name: .Target.coordination, + dependencies: [] + ), + .target( + name: .Target.core, + dependencies: [] + ), + .target( + name: .Target.dependencies, + dependencies: [] + ), + .testTarget( + name: "CommunicationsTests", + dependencies: [ + .init(stringLiteral: .Target.communications) + ], + path: "Tests/Communications" + ), + .testTarget( + name: "CoordinationTests", + dependencies: [ + .init(stringLiteral: .Target.coordination) + ], + path: "Tests/Coordination" + ), + .testTarget( + name: "CoreTests", + dependencies: [ + .init(stringLiteral: .Target.core) + ], + path: "Tests/Core" + ), + .testTarget( + name: "DependenciesTests", + dependencies: [ + .init(stringLiteral: .Target.dependencies) + ], + path: "Tests/Dependencies" + ), +] + +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) +targetsLibrary.append(.Target.persistence) +targetsPackage.append(contentsOf: [ + .target( + name: .Target.persistence, + dependencies: [] + ), + .testTarget( + name: "PersistenceTests", + dependencies: [ + .init(stringLiteral: .Target.persistence) + ], + path: "Tests/Persistence", + resources: [ + .process("Resources") + ] + ), +]) #endif +// MARK: - Package + let package = Package( - name: "SwiftLibs", + name: .Package.name, platforms: [ .iOS(.v15), .macOS(.v12), @@ -27,82 +99,26 @@ let package = Package( ], products: [ .library( - name: "SwiftLibs", - targets: [ - "Communications", - "Coordination", - "Core", - "Dependencies", - "Persistence" - ] + name: .Package.name, + targets: targetsLibrary ), ], dependencies: [], - targets: [ - .target( - name: "Communications", - dependencies: [] - ), - .target( - name: "Coordination", - dependencies: [], - exclude: excludePlatforms - ), - .target( - name: "Core", - dependencies: [] - ), - .target( - name: "Dependencies", - dependencies: [] - ), - .target( - name: "Persistence", - dependencies: [] - ), - .testTarget( - name: "CommunicationsTests", - dependencies: [ - "Communications" - ], - path: "Tests/Communications" - ), - .testTarget( - name: "CoordinationTests", - dependencies: [ - "Coordination" - ], - path: "Tests/Coordination", - exclude: excludePlatforms - ), - .testTarget( - name: "CoreTests", - dependencies: [ - "Core" - ], - path: "Tests/Core" - ), - .testTarget( - name: "DependenciesTests", - dependencies: [ - "Dependencies" - ], - path: "Tests/Dependencies" - ), - .testTarget( - name: "PersistenceTests", - dependencies: [ - "Persistence" - ], - path: "Tests/Persistence" - ), - ] + targets: targetsPackage ) // MARK: - String+Constants private extension String { - enum PlatformFolder { - static let iOS = "Platform/iOS" + enum Package { + static let name = "SwiftLibs" + } + + enum Target { + static let communications = "Communications" + static let coordination = "Coordination" + static let core = "Core" + static let dependencies = "Dependencies" + static let persistence = "Persistence" } } diff --git a/Sources/Communications/Classes/MockURLProtocol.swift b/Sources/Communications/Classes/MockURLProtocol.swift index 892f1dd..f4122a6 100644 --- a/Sources/Communications/Classes/MockURLProtocol.swift +++ b/Sources/Communications/Classes/MockURLProtocol.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) import Foundation /// This class overrides the `URLProtocol` protocol used by the `URLSession` to handle the loading of protocol-specific URL data so it is possible to mock URL response for testing purposes. @@ -116,3 +117,4 @@ public struct MockURLResponse { } } +#endif diff --git a/Sources/Communications/Use Cases/MakeURLRequestUseCase.swift b/Sources/Communications/Use Cases/MakeURLRequestUseCase.swift index 099fec1..f483f8a 100644 --- a/Sources/Communications/Use Cases/MakeURLRequestUseCase.swift +++ b/Sources/Communications/Use Cases/MakeURLRequestUseCase.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) import Foundation /// This use case generate a url request out of a given endpoint. @@ -55,3 +56,4 @@ public struct MakeURLRequestUseCase { } } +#endif diff --git a/Sources/Coordination/Platform/iOS/Routers/BaseNavigationRouter.swift b/Sources/Coordination/Routers/BaseNavigationRouter.swift similarity index 99% rename from Sources/Coordination/Platform/iOS/Routers/BaseNavigationRouter.swift rename to Sources/Coordination/Routers/BaseNavigationRouter.swift index dd437d1..7b0ba78 100644 --- a/Sources/Coordination/Platform/iOS/Routers/BaseNavigationRouter.swift +++ b/Sources/Coordination/Routers/BaseNavigationRouter.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#if os(iOS) import UIKit /// This is a base class for the `NavigationRouter` concrete router implementations. @@ -70,3 +71,4 @@ extension BaseNavigationRouter: UINavigationControllerDelegate { } } +#endif diff --git a/Sources/Coordination/Platform/iOS/Routers/ModalNavigationRouter.swift b/Sources/Coordination/Routers/ModalNavigationRouter.swift similarity index 99% rename from Sources/Coordination/Platform/iOS/Routers/ModalNavigationRouter.swift rename to Sources/Coordination/Routers/ModalNavigationRouter.swift index 4f52159..b87fec5 100644 --- a/Sources/Coordination/Platform/iOS/Routers/ModalNavigationRouter.swift +++ b/Sources/Coordination/Routers/ModalNavigationRouter.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#if os(iOS) import UIKit /// This class is responsible for showing view controllers modally, as it is a concrete implementation of the `Router` protocol. @@ -88,3 +89,4 @@ private extension ModalNavigationRouter { } } +#endif diff --git a/Sources/Coordination/Platform/iOS/Routers/PushNavigationRouter.swift b/Sources/Coordination/Routers/PushNavigationRouter.swift similarity index 99% rename from Sources/Coordination/Platform/iOS/Routers/PushNavigationRouter.swift rename to Sources/Coordination/Routers/PushNavigationRouter.swift index d4e999c..8cac7fe 100644 --- a/Sources/Coordination/Platform/iOS/Routers/PushNavigationRouter.swift +++ b/Sources/Coordination/Routers/PushNavigationRouter.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#if os(iOS) import UIKit /// This class is responsible for pushing view controllers into a navigation controller, as it is a concrete implementation of the `Router` protocol. @@ -66,3 +67,4 @@ extension PushNavigationRouter: Router { } } +#endif diff --git a/Sources/Coordination/Platform/iOS/Routers/WindowRouter.swift b/Sources/Coordination/Routers/WindowRouter.swift similarity index 98% rename from Sources/Coordination/Platform/iOS/Routers/WindowRouter.swift rename to Sources/Coordination/Routers/WindowRouter.swift index f9d7431..1cc887f 100644 --- a/Sources/Coordination/Platform/iOS/Routers/WindowRouter.swift +++ b/Sources/Coordination/Routers/WindowRouter.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#if os(iOS) import UIKit /// This class is responsible for populating the window of an application. @@ -45,3 +46,4 @@ public class WindowRouter: Router { } } +#endif diff --git a/Sources/Persistence/Classes/Fetcher.swift b/Sources/Persistence/Classes/Fetcher.swift index c69e715..e69b44e 100644 --- a/Sources/Persistence/Classes/Fetcher.swift +++ b/Sources/Persistence/Classes/Fetcher.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#if canImport(Combine) && canImport(CoreData) import Combine import CoreData @@ -167,3 +168,4 @@ public enum Change: Hashable { case section(SectionUpdate) case object(ObjectUpdate) } +#endif diff --git a/Sources/Persistence/Protocols/Service.swift b/Sources/Persistence/Protocols/Service.swift index 358ebe1..0e5b67f 100644 --- a/Sources/Persistence/Protocols/Service.swift +++ b/Sources/Persistence/Protocols/Service.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#if canImport(CoreData) import CoreData public protocol Service { @@ -38,3 +39,4 @@ public protocol Service { func save(childContext context: NSManagedObjectContext) throws } +#endif diff --git a/Tests/Communications/Use Cases/MakeURLRequestUseCaseTests.swift b/Tests/Communications/Cases/Use Cases/MakeURLRequestUseCaseTests.swift similarity index 98% rename from Tests/Communications/Use Cases/MakeURLRequestUseCaseTests.swift rename to Tests/Communications/Cases/Use Cases/MakeURLRequestUseCaseTests.swift index 7499bb1..ab95f5d 100644 --- a/Tests/Communications/Use Cases/MakeURLRequestUseCaseTests.swift +++ b/Tests/Communications/Cases/Use Cases/MakeURLRequestUseCaseTests.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#if os(iOS) || os(macOS) || os(tvOS) || os(watchOS) import Communications import Foundation import XCTest @@ -141,3 +142,4 @@ private struct TestEndpoint: Endpoint { } } +#endif diff --git a/Tests/Coordination/Platform/iOS/Protocols/CoordinatorTests.swift b/Tests/Coordination/Cases/Protocols/CoordinatorTests.swift similarity index 99% rename from Tests/Coordination/Platform/iOS/Protocols/CoordinatorTests.swift rename to Tests/Coordination/Cases/Protocols/CoordinatorTests.swift index 4a61d28..516b323 100644 --- a/Tests/Coordination/Platform/iOS/Protocols/CoordinatorTests.swift +++ b/Tests/Coordination/Cases/Protocols/CoordinatorTests.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#if canImport(UIKit) import Coordination import UIKit import XCTest @@ -139,3 +140,4 @@ final class CoordinatorTests: XCTestCase { } } +#endif diff --git a/Tests/Coordination/Platform/iOS/Helpers/TestCoordinators.swift b/Tests/Coordination/Helpers/TestCoordinators.swift similarity index 98% rename from Tests/Coordination/Platform/iOS/Helpers/TestCoordinators.swift rename to Tests/Coordination/Helpers/TestCoordinators.swift index 0379685..0212dd0 100644 --- a/Tests/Coordination/Platform/iOS/Helpers/TestCoordinators.swift +++ b/Tests/Coordination/Helpers/TestCoordinators.swift @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#if canImport(UIKit) import Coordination import UIKit @@ -108,3 +109,4 @@ class SpyRouter: Router { class SomeViewController: UIViewController {} class SomeOtherViewController: UIViewController {} +#endif diff --git a/Tests/Dependencies/Property Wrappers/DependencyTests.swift b/Tests/Dependencies/Cases/Property Wrappers/DependencyTests.swift similarity index 100% rename from Tests/Dependencies/Property Wrappers/DependencyTests.swift rename to Tests/Dependencies/Cases/Property Wrappers/DependencyTests.swift diff --git a/Tests/Dependencies/Services/DependencyServiceTests.swift b/Tests/Dependencies/Cases/Services/DependencyServiceTests.swift similarity index 100% rename from Tests/Dependencies/Services/DependencyServiceTests.swift rename to Tests/Dependencies/Cases/Services/DependencyServiceTests.swift diff --git a/Tests/Persistence/Classes/FetcherTests.swift b/Tests/Persistence/Cases/Classes/FetcherTests.swift similarity index 100% rename from Tests/Persistence/Classes/FetcherTests.swift rename to Tests/Persistence/Cases/Classes/FetcherTests.swift diff --git a/Tests/Persistence/Extensions/URL+DevicesTests.swift b/Tests/Persistence/Cases/Extensions/URL+DevicesTests.swift similarity index 100% rename from Tests/Persistence/Extensions/URL+DevicesTests.swift rename to Tests/Persistence/Cases/Extensions/URL+DevicesTests.swift diff --git a/Tests/Persistence/Helpers/TestEntity.swift b/Tests/Persistence/Helpers/TestEntity.swift new file mode 100644 index 0000000..691f3de --- /dev/null +++ b/Tests/Persistence/Helpers/TestEntity.swift @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the SwiftLibs open source project +// +// Copyright (c) 2023 Röck+Cöde VoF. and the SwiftLibs project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of SwiftLibs project authors +// +//===----------------------------------------------------------------------===// + +import Foundation +import CoreData + +@objc(TestEntity) +public class TestEntity: NSManagedObject {} + +// MARK: - Fetch requests + +extension TestEntity { + + // MARK: Functions + + @nonobjc public class func fetchRequest() -> NSFetchRequest { + return NSFetchRequest(entityName: "TestEntity") + } + +} diff --git a/Tests/Persistence/Helpers/TestPersistenceService.swift b/Tests/Persistence/Helpers/TestPersistenceService.swift index 2ebb19d..bac652b 100644 --- a/Tests/Persistence/Helpers/TestPersistenceService.swift +++ b/Tests/Persistence/Helpers/TestPersistenceService.swift @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// import CoreData +import Foundation import Persistence struct TestPersistenceService { diff --git a/Tests/Persistence/Helpers/TestModel.xcdatamodeld/Model.xcdatamodel/contents b/Tests/Persistence/Resources/TestModel.xcdatamodeld/Model.xcdatamodel/contents similarity index 88% rename from Tests/Persistence/Helpers/TestModel.xcdatamodeld/Model.xcdatamodel/contents rename to Tests/Persistence/Resources/TestModel.xcdatamodeld/Model.xcdatamodel/contents index 4c66cba..e1702d8 100644 --- a/Tests/Persistence/Helpers/TestModel.xcdatamodeld/Model.xcdatamodel/contents +++ b/Tests/Persistence/Resources/TestModel.xcdatamodeld/Model.xcdatamodel/contents @@ -1,4 +1,4 @@ - + \ No newline at end of file