diff --git a/.github/workflows/build-documentation.yml b/.github/workflows/build-documentation.yml new file mode 100644 index 0000000..6a6f6ba --- /dev/null +++ b/.github/workflows/build-documentation.yml @@ -0,0 +1,19 @@ +# .github/workflows/build-documentation.yml + +name: build-documentation + +on: + # Run on push to main branch + push: + branches: + - main + + # Dispatch if triggered using Github (website) + workflow_dispatch: + +jobs: + Build-documentation: + runs-on: macos-latest + steps: + - name: Build documentation + uses: 0xWDG/build-documentation@main diff --git a/.github/workflows/build-multiplatform.yml b/.github/workflows/build-multiplatform.yml new file mode 100644 index 0000000..4f49cf9 --- /dev/null +++ b/.github/workflows/build-multiplatform.yml @@ -0,0 +1,17 @@ +# .github/workflows/build-multiplatform.yml + +name: Build-Packages + +on: + # Run on pull_request + pull_request: + + # Dispatch if triggered using Github (website) + workflow_dispatch: + +jobs: + Build-Packages: + runs-on: macos-latest + steps: + - name: Build Swift Packages + uses: 0xWDG/build-swift@main \ No newline at end of file diff --git a/.github/workflows/swiftlint.yml b/.github/workflows/swiftlint.yml new file mode 100644 index 0000000..8d88883 --- /dev/null +++ b/.github/workflows/swiftlint.yml @@ -0,0 +1,16 @@ +name: Run Swiftlint +on: + push: + pull_request: + workflow_dispatch: + +jobs: + swiftlint: + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + + - name: SwiftLint + run: | + brew install swiftlint + swiftlint --reporter github-actions-logging --strict \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..1333bf5 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,23 @@ +name: Run tests on Linux and macOS +on: + push: + workflow_dispatch: + +jobs: + test_linux: + if: true + runs-on: ubuntu-latest + continue-on-error: true + steps: + - uses: actions/checkout@v3 + + - name: Swift test + run: swift test + + test_macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@v3 + + - name: Swift test + run: swift test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fbd424d --- /dev/null +++ b/.gitignore @@ -0,0 +1,63 @@ +## User settings +xcuserdata/ + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Obj-C/Swift specific +*.hmap + +## App packaging +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +### Swift Package Manager +Packages/ +Package.pins +Package.resolved +# *.xcodeproj +# +# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata +# hence it is not needed unless you have added a package configuration file to your project +.swiftpm +.build/ + +### CocoaPods +Pods/ +*.xcworkspace + +### Carthage +Carthage/Checkouts +Carthage/Build/ + +### Accio dependency management +Dependencies/ +.accio/ + +### fastlane +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +### Code Injection +iOSInjectionProject/ diff --git a/.spi.yml b/.spi.yml new file mode 100644 index 0000000..32c9139 --- /dev/null +++ b/.spi.yml @@ -0,0 +1,4 @@ +version: 1 +builder: + configs: + - documentation_targets: [spm-template] \ No newline at end of file diff --git a/.spm.swift b/.spm.swift new file mode 100755 index 0000000..5d520ea --- /dev/null +++ b/.spm.swift @@ -0,0 +1,313 @@ +#!/usr/bin/swift + +// +// spm.swift +// This script will add a header to all .swift files in the current directory. +// And can test the package for various platforms. +// +// Created by Wesley de Groot on 2024-08-06. +// https://wesleydegroot.nl +// +// https://github.com/0xWDG/spm-template +// MIT License + +// To compile this script to a binary, run: +// swiftc .spm.swift -o spm + +import Foundation + +let fileManager = FileManager.default +var internalProductName: String? +var productName: String { + get { + if let productName = internalProductName { + return productName + } + + if fileManager.fileExists(atPath: "Package.swift") { + guard let package = try? String(contentsOf: URL(fileURLWithPath: "Package.swift"), encoding: .utf8), + let productName = package + .components(separatedBy: .newlines) + .first(where: { $0.contains("name:") })? + .components(separatedBy: .whitespaces) + .last? + .replacingOccurrences(of: "\"", with: "") + .replacingOccurrences(of: ",", with: "") else { + printC("Could not find product name in Package.swift", color: CLIColors.red) + exit(2) + } + + return productName + } else { + printC("Package.swift not found, please provide package name", color: CLIColors.red) + return "" + } + } + set { + internalProductName = newValue + } +} + +struct CLIColors { + static let red = "\u{001B}[0;31m" + static let green = "\u{001B}[0;32m" + static let yellow = "\u{001B}[0;33m" + static let blue = "\u{001B}[0;34m" + static let magenta = "\u{001B}[0;35m" + static let cyan = "\u{001B}[0;36m" + static let white = "\u{001B}[0;37m" + static let reset = "\u{001B}[0;0m" +} + +func printUsage() { + print("Usage: \(CommandLine.arguments[0]) ") + print("Commands:") + print(" create - Add a header to all .swift files in the current directory") + print(" header - Update the header for all .swift files in the current directory") + print(" readme - Generate a README.md file for the package") + print(" build - Build the package for all platforms") + print(" test - Test the package for all platforms") +} + +func printC(_ text: String, color: String = CLIColors.reset) { + print("\(color)\(text)\(CLIColors.reset)") +} + +if CommandLine.argc < 2 { + printUsage() + exit(1) +} + +if CommandLine.arguments[1] == "create" && CommandLine.argc < 3 { + print("Usage: \(CommandLine.arguments[0]) create ") + exit(1) +} + +if CommandLine.arguments[1] == "create" && CommandLine.argc == 3 { + productName = CommandLine.arguments[2] + + if !fileManager.fileExists(atPath: "Package.swift") { + let process = Process() + process.launchPath = "/usr/bin/env" + process.arguments = ["swift", "package", "init", "--name", productName] + process.launch() + process.waitUntilExit() + } + + /// Change the first line of the Package.swift file + let package = try String(contentsOf: URL(fileURLWithPath: "Package.swift"), encoding: .utf8) + let newPackage = package + .components(separatedBy: .newlines) + .enumerated() + .map { index, line in + if index == 0 { + return "// swift-tools-version: 5.8.0" + } else { + return line + } + } + .joined(separator: "\n") + try? newPackage.write(to: URL(fileURLWithPath: "Package.swift"), atomically: true, encoding: .utf8) + printC("Downgraded swift-tools-version to 5.8.0", color: CLIColors.green) + + let spi = """ +version: 1 +builder: + configs: + - documentation_targets: [\(productName)] +""" + try spi.write(to: URL(fileURLWithPath: ".spi.yml"), atomically: true, encoding: .utf8) + + header() +} + +if CommandLine.arguments[1] == "header" { + header() +} + +if CommandLine.arguments[1] == "readme" { + generateReadme() +} + +if CommandLine.arguments[1] == "build" { + let platforms = ["iOS", "tvOS", "xrOS", "watchOS", "macOS"] + + printC("Build \(productName) for all platforms...") + + for platform in platforms { + printC("Building \(productName) on \(platform).\r") + let process = Process() + process.launchPath = "/usr/bin/env" + process.arguments = [ + "xcrun", + "xcodebuild", + "clean", + "build", + "-quiet", + "-scheme", productName, + "-destination", "generic/platform=\(platform)" + ] + process.launch() + process.waitUntilExit() + // Check if the process was successful + if process.terminationStatus != 0 { + printC("Failed to build for \(platform)", color: CLIColors.red) + exit(3) + } else { + printC("Build for \(platform) successful", color: CLIColors.green) + } + } +} + +if CommandLine.arguments[1] == "test" { + printC("Testing is not yet implemented", color: CLIColors.red) + exit(99) +} + +func header() { + // Search for all .swift files + let enumerator = fileManager.enumerator(atPath: ".") + while let element = enumerator?.nextObject() as? String { + if element.hasSuffix(".swift") { + var headerLines = 0 + + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy-MM-dd" + let date = dateFormatter.string(from: Date()) + + var createdBy = "// Created by Wesley de Groot on \(date)." + let file = element + let path = URL(fileURLWithPath: file) + guard let contents = try? String(contentsOf: path, encoding: .utf8) else { + printC("Failed to read \(file)", color: CLIColors.red) + continue + } + let filename = file.components(separatedBy: "/").last + var lines = contents.components(separatedBy: .newlines) + + if lines.isEmpty { + break + } + + if lines[0].hasPrefix("#!") || file == "Package.swift" { + continue + } + + for line in lines { + if line.hasPrefix("//") { + if line.contains("Created by") { + createdBy = line + } + + headerLines += 1 + } else { + break + } + } + + lines.removeFirst(Int(headerLines)) + + let header = [ + "//", + "// \(filename ?? "")", + "// \(productName)", + "//", + createdBy, + "// https://wesleydegroot.nl", + "//", + "// https://github.com/0xWDG/\(productName)", + "// MIT License", + "//" + ] + + lines.insert(contentsOf: header, at: 0) + let newContents = lines.joined(separator: "\n") + do { + try newContents.write(to: path, atomically: true, encoding: .utf8) + printC("Updated header for \(file)", color: CLIColors.green) + } catch { + printC("Failed to update header for \(file)", color: CLIColors.red) + } + } + } + + generateReadme() +} + +func generateReadme() { + var readme = """ +# PACKAGENAME + +PACKAGENAME is a Swift Package for ... + +[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2F0xWDG%2FPACKAGENAME%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/0xWDG/PACKAGENAME) +[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2F0xWDG%2FPACKAGENAME%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/0xWDG/PACKAGENAME) +[![Swift Package Manager](https://img.shields.io/badge/SPM-compatible-brightgreen.svg)](https://swift.org/package-manager) +![License](https://img.shields.io/github/license/0xWDG/PACKAGENAME) + +## Requirements + +- Swift 5.9+ (Xcode 15+) +- iOS 13+, macOS 10.15+ + +## Installation (Pakage.swift) + +```swift +dependencies: [ + .package(url: "https://github.com/0xWDG/PACKAGENAME.git", branch: "main"), +], +targets: [ + .target(name: "MyTarget", dependencies: [ + .product(name: "PACKAGENAME", package: "PACKAGENAME"), + ]), +] +``` + +## Installation (Xcode) + +1. In Xcode, open your project and navigate to **File** → **Swift Packages** → **Add Package Dependency...** +2. Paste the repository URL (`https://github.com/0xWDG/PACKAGENAME`) and click **Next**. +3. Click **Finish**. + +## Usage + +```swift +import SwiftUI +import PACKAGENAME + +struct ContentView: View { + var body: some View { + VStack { + /// ... + } + .padding() + } +} +``` + +## Contact + +We can get in touch via [Mastodon](https://mastodon.social/@0xWDG), [Twitter/X](https://twitter.com/0xWDG), [Discord](https://discordapp.com/users/918438083861573692), [Email](mailto:email@wesleydegroot.nl), [Website](https://wesleydegroot.nl). + +Interested learning more about Swift? [Check out my blog](https://wesleydegroot.nl/blog/). +""" + + readme = readme.replacingOccurrences(of: "PACKAGENAME", with: productName) + + try? readme.write(to: URL(fileURLWithPath: "README.md"), atomically: true, encoding: .utf8) +} + +if CommandLine.arguments[1] != "executable" { + let process = Process() + process.launchPath = "/usr/bin/env" + process.arguments = ["swiftc", CommandLine.arguments[0], "-o", "spm"] + process.launch() + process.waitUntilExit() + + if process.terminationStatus != 0 { + printC("Failed to compile script", color: CLIColors.red) + exit(4) + } else { + printC("Script compiled successfully", color: CLIColors.green) + } +} \ No newline at end of file diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 0000000..c6a5a2f --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,16 @@ +excluded: + - "*resource_bundle_accessor*" # SwiftPM Generated + - ".build/*" + +opt_in_rules: + - missing_docs + - empty_count + - empty_string + - toggle_bool + - unused_optional_binding + - valid_ibinspectable + - modifier_order + - first_where + - fatal_error_message + - force_unwrapping + diff --git a/LICENCE.md b/LICENCE.md new file mode 100644 index 0000000..e30907d --- /dev/null +++ b/LICENCE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Wesley de Groot, email@WesleydeGroot.nl + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..a3f85f4 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +# spm-template + +spm-template is a Swift Package for ... + +[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2F0xWDG%2Fspm-template%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/0xWDG/spm-template) +[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2F0xWDG%2Fspm-template%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/0xWDG/spm-template) +[![Swift Package Manager](https://img.shields.io/badge/SPM-compatible-brightgreen.svg)](https://swift.org/package-manager) +![License](https://img.shields.io/github/license/0xWDG/spm-template) + +## Requirements + +- Swift 5.9+ (Xcode 15+) +- iOS 13+, macOS 10.15+ + +## Installation (Pakage.swift) + +```swift +dependencies: [ + .package(url: "https://github.com/0xWDG/spm-template.git", branch: "main"), +], +targets: [ + .target(name: "MyTarget", dependencies: [ + .product(name: "spm-template", package: "spm-template"), + ]), +] +``` + +## Installation (Xcode) + +1. In Xcode, open your project and navigate to **File** → **Swift Packages** → **Add Package Dependency...** +2. Paste the repository URL (`https://github.com/0xWDG/spm-template`) and click **Next**. +3. Click **Finish**. + +## Usage + +```swift +import SwiftUI +import spm-template + +struct ContentView: View { + var body: some View { + VStack { + /// ... + } + .padding() + } +} +``` + +## Contact + +We can get in touch via [Mastodon](https://mastodon.social/@0xWDG), [Twitter/X](https://twitter.com/0xWDG), [Discord](https://discordapp.com/users/918438083861573692), [Email](mailto:email@wesleydegroot.nl), [Website](https://wesleydegroot.nl). + +Interested learning more about Swift? [Check out my blog](https://wesleydegroot.nl/blog/). \ No newline at end of file diff --git a/spm b/spm new file mode 100755 index 0000000..b6e7deb Binary files /dev/null and b/spm differ