I have managed to run SwiftLint as plugin for my project
struct Linting: BuildToolPlugin {
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
let swiftLintConfigFile = context.package.directory.appending(".swiftlint.yml")
let genSourcesDir = context.pluginWorkDirectory.appending("output")
return [
.buildCommand(
displayName: "Running SwiftLint for \(target.name)",
executable: try context.tool(named: "swiftlint").path,
arguments: [
"lint",
"--config",
swiftLintConfigFile
],
environment: [:],
outputFiles: [genSourcesDir]
)
]
}
}
everything is working as expected and I can see the errors/warnings of SwiftLint but the problem is That I always get Command PhaseScriptExecution failed with a nonzero exit code
Here is my Package.swift
let package = Package(
name: "APP",
products: [
.library(name: "AppFeature", targets: ["AppFeature"]),
.library(name: "Models", targets: ["Models"]),
.plugin(name: "Linting", targets: ["Linting"])
],
dependencies: [],
targets: [
.target(name: "AppFeature", dependencies: ["Models"], plugins: ["Linting"]),
.target(name: "Models"),
.binaryTarget(name: "SwiftLintBinary", path: "Sources/SwiftLintBinary.artifactbundle"),
.plugin(
name: "Linting",
capability: .buildTool(),
dependencies: [
"SwiftLintBinary"
]
),
.testTarget(name: "AppFeatureTests", dependencies: ["AppFeature"]),
]
)
The Package belong to a Xcode project like the following.
I also have checked what does the Error I am getting means
Error: You don’t have permission to save the file “d42b39293bc4ddcfb20c48bf35251e7209d7ddee87edd739b0bc0bab05584478.plist” in the folder “8FE8CC02-8D70-373F-99BE-864A503CD73A”.
it turned out that the 8FE8CC02-8D70-373F-99BE-864A503CD73A is a folder being used by SwiftLint to cache some findings
.//Library/Caches/SwiftLint/0.49.0/8FE8CC02-8D70-373F-99BE-864A503CD73A
the weird thing is if I run the swiftlint from the Mac terminal it just works using ./Sources/SwiftLintBinary.artifactbundle/swiftlint-0.49.0-macos/bin/swiftlint but from Xcode it doesn't, any help would be appreciated.
Related
I'm using SPM to achieve modular architecture in my iOS Xcode project. That's my package.swift:
let targets: [Target] = [
.target(name: "Home", dependencies: ["Texture", ...]),
.testTarget(name: "HomeTests", dependencies: ["Home", ...]),
.target(name: "Inbox”, dependencies: []),
.testTarget(name: "Inbox”Tests", dependencies: ["Inbox", ...]),
.target(name: “Settings”, dependencies: []),
.testTarget(name: "SettingsTests", dependencies: ["Settings", ...]),
]
let package = Package(
name: "MyPackage",
platforms: [.iOS(.v14), .macOS(.v10_15)],
products: targets.filter { !$0.isTest }.map { .library(name: $0.name, targets: [$0.name]) },
dependencies: [...],
targets: targets)
)
As you can see I have test target for each module. TestTargets contain unit tests.
How can I run all the test targets together? For now I can only run each test target independently and it takes too much time to test the whole app.
I am trying to build a Swift package, where one of the targets must depend on a different version of a library depending on whether it is being built for iOS or MacOS.
For iOS, the dependency is packaged as an .xcframework, whereas for MacOS it is packaged as a system library.
So my dependencies package looks like this:
// swift-tools-version:5.6
import PackageDescription
let package = Package(
name: "LibFoo",
products: [
.library(name: "LibFooFramework", targets: ["LibFooFramework"]),
.library(name: "ClibFoo", targets: ["ClibFoo"])
],
targets: [
.binaryTarget(
name: "LibFooFramework",
path: "path/to/LibFooFramework.xcframework"
),
.systemLibrary(
name: "ClibFoo",
pkgConfig: "libFoo"
)
]
)
So then in my client package, I want to use one of these dependencies depending on the target platform.
I have tried this:
// swift-tools-version:5.6
import PackageDescription
#if os(iOS)
let conditionalTarget: Target = .target(
name: "MyLib",
dependencies: [
.product(name: "LibFooFramework", package: "LibFooFramework")
]
)
#else
let CVulkanUtilsTarget: Target = .target(
name: "MyLib",
dependencies: [
.product(name: "ClibFoo", package: "LibFoo")
]
)
#endif
let package = Package(
name: "MyLib",
products: [
.library(name: "MyLib", targets: ["MyLib"]),
],
dependencies: [
.package(url: "https://github.com/spencerkohan/LibFoo", branch:"master")
],
targets: [
.library(
name: "LibFooFramework",
path: "path/to/LibFooFramework.xcframework"
),
]
)
But it seems that the package manager always takes the else branch, even if the package is being built for iOS. I guess this is because the os target of the Package.swift will always be the build environment and not the target.
But is there any way to achieve this type of conditional dependency?
Is there a way to suppress all warnings coming from my SPM Package in XCode?!
⚠️found 1 file(s) which are unhandled; explicitly declare them as
resources or exclude from the target
This warning shows because my SPM package contains .txt file.
I tried adding swiftSettings: [.unsafeFlags(["-suppress-warnings"])] in package.swift but didn't work.
// swift-tools-version:5.5
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "Sourcery",
platforms: [.macOS(.v10_13)],
dependencies: [
.package(
url: "https://github.com/pointfreeco/swift-snapshot-testing.git",
from: "1.9.0"
)
],
targets: [
.executableTarget(
name: "Sourcery",
dependencies: []
),
.testTarget(
name: "SourceryTests",
dependencies: [.product(name: "SnapshotTesting", package: "swift-snapshot-testing")]
)
]
)
Looks like the exclude parameter supports folders as well. So I organized all .txt file in a folder and now I got rid of the warnings :)
import PackageDescription
let package = Package(
name: "Sourcery",
platforms: [.macOS(.v10_13)],
dependencies: [
.package(
url: "https://github.com/pointfreeco/swift-snapshot-testing.git",
from: "1.9.0"
)
],
targets: [
.executableTarget(
name: "Sourcery",
dependencies: [],
exclude: ["Templates"]
),
.testTarget(
name: "SourceryTests",
dependencies: [.product(name: "SnapshotTesting", package: "swift-snapshot-testing")],
exclude: ["__Snapshots__"]
)
]
)
I'm migrating a library built and tested as an Xcode Project to Swift Package Manager. The project contains 3 targets: the library itself, the same library but with different dependency and the test (application) target.
So far, porting the library was easy.
Now I'm interested in building the same library with a different dependency (mocks) which could be tested.
In practice, the Package.swift file looks like this:
// swift-tools-version:5.4
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "TargetLibrary",
platforms: [
.iOS(.v14), .macOS(.v10_15)
],
products: [
.library(
name: "TargetLibrary",
targets: ["TargetLibrary"]
),
],
dependencies: [
.package(
url: "ssh://git#github.com/DependentLib",
.upToNextMinor(from: "1.3.18")
),
],
targets: [
.target(
name: "TargetLibrary",
dependencies: [
// Using the "main" dependency for the "TargetLibrary"
.product(name: "DependentLib", package: "DependentLib"),
],
path: "src",
sources: [
"sourcefiles"
],
publicHeadersPath: "SwiftPackage/include",
cxxSettings: [
.headerSearchPath("lib"),
]
),
// This target is virtually identical, to the previous one,
// the only difference is that it is using a different dependency library
// from the same package
.target(
name: "TargetLibraryWithMock",
dependencies: [
// Using the "mock" dependency for this library
.product(name: "DependentLibMock", package: "DependentLib"),
],
path: "src",
sources: [
"sourcefiles"
],
publicHeadersPath: "SwiftPackage/include",
cxxSettings: [
.headerSearchPath("lib"),
]
),
// Now testing the "TargetLibraryWithMock"
.testTarget()....
],
cxxLanguageStandard: .cxx14
)
Now, of course, if I just duplicate two targets, I'll get a target overlapping sources error
So, the question is:
How can I build two targets different only by the dependencies they include?
It looks like target dependency condition could have helped here
dependencies: [
.target(name: "DependentLib", condition: .when(configuration: .build)),
.target(name: "DependentLibMock", condition: .when(configuration: .test)),
]
but only platform-specific conditionals exist now. What could be solutions to this problem?
Graphical representation of the desired result:
I have an existing projects of a framework and library and would like them to use Swift Package Manager.
I have a Xcode 11 and have already already read Creating a Swift Package with Xcode.
After adding Package.swift to the project and an application target
import PackageDescription
let package = Package(
name: "MyLibrary",
platforms: [
.macOS(.v10_13),
],
products: [
.library(name: "MyLibrary", targets: ["MyLibrary"]),
],
dependencies: [
.package(url: "https://url/of/another/package/named/Utility", from: "1.0.0"),
],
targets: [
.target(name: "MyLibrary", dependencies: ["Utility"]),
.testTarget(name: "MyLibraryTests", dependencies: ["MyLibrary"]),
]
)
I get an error
No such module 'PackageDescription'
How can I import PackageDescription module?
I just added line below at the very first line of the Package.swift file and it worked for me.
// swift-tools-version:4.0
Note: Please do not write any thing even comment before this line
After that do not forget to run swift build command