如何使用 Swift 包管理器将 SwiftLint 与 iOS 应用集成?
How to integrate SwiftLint with an iOS app using Swift Package Manager?
我正在 Xcode 11(测试版 5)中创建一个新的 iOS 应用程序,我想尝试使用 Swift 包管理器而不是 CocoaPods 来管理依赖项。
使用 SwiftLint 和 CocoaPods 时的一个常见模式是添加 SwiftLint 作为依赖项,然后添加构建阶段以执行 ${PODS_ROOT}/SwiftLint/swiftlint
;这样所有开发人员最终都使用相同版本的 SwiftLint。
如果我尝试在 Xcode 中添加 SwiftLint 作为 SwiftPM 依赖项,我需要的可执行目标被禁用:
我可以通过在构建阶段创建一个没有产品或目标的虚拟 Package.swift
和 运行 swift run swiftlint
来伪造它,但感觉很古怪和奇怪:
// swift-tools-version:5.1
import PackageDescription
let package = Package(
name: "dummy-package",
products: [],
dependencies: [
.package(url: "https://github.com/realm/SwiftLint.git", from: "0.34.0")
],
targets: []
)
有没有不创建虚拟包的方法?或者 Swift 包管理器不是适合这个特定用例的工具?
所有 滥用 iOS 代码依赖管理器到 运行 构建工具的方法都很古怪。
对符合 SPM 的工具依赖项进行版本控制的正确方法是使用 Mint: A package manager that installs and runs Swift CLI packages. See also Better iOS projects: How to manage your tooling with mint。
我使用 xcodegen 生成一个 Xcode 项目,该项目能够 运行 脚本。这让我在开发包时看到 Xcode 中的 swiftlint 警告。
此工具从 project.yml definition. In that definition, you can add a script that runs swiftlint as a post compile task. Example.
创建一个 Xcode 项目
这种方法的优点:
- Xcode 中的 swiftlint 警告。
- Xcode 超出 SPM 提供范围的设置。
缺点:
- 您依赖的第三方工具可能会损坏或消失。但是,您可以随时删除此依赖项并返回编辑 Xcode.
中的 Package.swift
- 您需要学习编写 project.yml 个文件。
- 如果您使用 SPM 包,您需要自己生成包访问器。
关于生成包访问器的一句话。从 Xcode 项目工作时需要这样做,因为只有 SPM 会为项目生成文件 resource_bundle_accessor.swift
。如果你在用 Xcode 打开 Package.swift
后已经编译,文件应该在这里:
find ~/Library/Developer/Xcode/DerivedData* -iname resource_bundle_accessor.swift
您可以将它添加到项目中,但如果您正在创建一个框架,则 bundle 访问器可以像这样简单:
import class Foundation.Bundle
// This file is only used when using a xcodegen-generated project.
// Otherwise this file should not be in the path.
private class BundleFinder {}
extension Foundation.Bundle {
static var module = Bundle(for: BundleFinder.self)
}
不是完美的解决方案,但它有效。我找到了 here
- 修改
Package.swift
的目标部分
targets: [
// 1. Specify where to download the compiled swiftlint tool from.
.binaryTarget(
name: "SwiftLintBinary",
url: "https://github.com/realm/SwiftLint/releases/download/0.47.1/SwiftLintBinary-macos.artifactbundle.zip",
checksum: "cdc36c26225fba80efc3ac2e67c2e3c3f54937145869ea5dbcaa234e57fc3724"
),
// 2. Define the SPM plugin.
.plugin(
name: "SwiftLintPlugin",
capability: .buildTool(),
dependencies: ["SwiftLintBinary"]
),
// 3. Use the plugin in your project.
.target(
name: "##NameOfYourMainTarget",
dependencies: ["SwiftLintPlugin"] // dependency on plugin
)
]
- 创建
Plugins/SwiftLintPlugin/SwiftLintPlugin.swift
import PackagePlugin
@main
struct SwiftLintPlugin: BuildToolPlugin {
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
return [
.buildCommand(
displayName: "Running SwiftLint for \(target.name)",
executable: try context.tool(named: "swiftlint").path,
arguments: [
"lint",
"--in-process-sourcekit",
"--path",
target.directory.string,
"--config",
"\(context.package.directory.string)/.swiftlint.yml" // IMPORTANT! Path to your swiftlint config
],
environment: [:]
)
]
}
}
我正在 Xcode 11(测试版 5)中创建一个新的 iOS 应用程序,我想尝试使用 Swift 包管理器而不是 CocoaPods 来管理依赖项。
使用 SwiftLint 和 CocoaPods 时的一个常见模式是添加 SwiftLint 作为依赖项,然后添加构建阶段以执行 ${PODS_ROOT}/SwiftLint/swiftlint
;这样所有开发人员最终都使用相同版本的 SwiftLint。
如果我尝试在 Xcode 中添加 SwiftLint 作为 SwiftPM 依赖项,我需要的可执行目标被禁用:
我可以通过在构建阶段创建一个没有产品或目标的虚拟 Package.swift
和 运行 swift run swiftlint
来伪造它,但感觉很古怪和奇怪:
// swift-tools-version:5.1
import PackageDescription
let package = Package(
name: "dummy-package",
products: [],
dependencies: [
.package(url: "https://github.com/realm/SwiftLint.git", from: "0.34.0")
],
targets: []
)
有没有不创建虚拟包的方法?或者 Swift 包管理器不是适合这个特定用例的工具?
所有 滥用 iOS 代码依赖管理器到 运行 构建工具的方法都很古怪。
对符合 SPM 的工具依赖项进行版本控制的正确方法是使用 Mint: A package manager that installs and runs Swift CLI packages. See also Better iOS projects: How to manage your tooling with mint。
我使用 xcodegen 生成一个 Xcode 项目,该项目能够 运行 脚本。这让我在开发包时看到 Xcode 中的 swiftlint 警告。
此工具从 project.yml definition. In that definition, you can add a script that runs swiftlint as a post compile task. Example.
创建一个 Xcode 项目这种方法的优点:
- Xcode 中的 swiftlint 警告。
- Xcode 超出 SPM 提供范围的设置。
缺点:
- 您依赖的第三方工具可能会损坏或消失。但是,您可以随时删除此依赖项并返回编辑 Xcode. 中的 Package.swift
- 您需要学习编写 project.yml 个文件。
- 如果您使用 SPM 包,您需要自己生成包访问器。
关于生成包访问器的一句话。从 Xcode 项目工作时需要这样做,因为只有 SPM 会为项目生成文件 resource_bundle_accessor.swift
。如果你在用 Xcode 打开 Package.swift
后已经编译,文件应该在这里:
find ~/Library/Developer/Xcode/DerivedData* -iname resource_bundle_accessor.swift
您可以将它添加到项目中,但如果您正在创建一个框架,则 bundle 访问器可以像这样简单:
import class Foundation.Bundle
// This file is only used when using a xcodegen-generated project.
// Otherwise this file should not be in the path.
private class BundleFinder {}
extension Foundation.Bundle {
static var module = Bundle(for: BundleFinder.self)
}
不是完美的解决方案,但它有效。我找到了 here
- 修改
Package.swift
的目标部分
targets: [
// 1. Specify where to download the compiled swiftlint tool from.
.binaryTarget(
name: "SwiftLintBinary",
url: "https://github.com/realm/SwiftLint/releases/download/0.47.1/SwiftLintBinary-macos.artifactbundle.zip",
checksum: "cdc36c26225fba80efc3ac2e67c2e3c3f54937145869ea5dbcaa234e57fc3724"
),
// 2. Define the SPM plugin.
.plugin(
name: "SwiftLintPlugin",
capability: .buildTool(),
dependencies: ["SwiftLintBinary"]
),
// 3. Use the plugin in your project.
.target(
name: "##NameOfYourMainTarget",
dependencies: ["SwiftLintPlugin"] // dependency on plugin
)
]
- 创建
Plugins/SwiftLintPlugin/SwiftLintPlugin.swift
import PackagePlugin
@main
struct SwiftLintPlugin: BuildToolPlugin {
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
return [
.buildCommand(
displayName: "Running SwiftLint for \(target.name)",
executable: try context.tool(named: "swiftlint").path,
arguments: [
"lint",
"--in-process-sourcekit",
"--path",
target.directory.string,
"--config",
"\(context.package.directory.string)/.swiftlint.yml" // IMPORTANT! Path to your swiftlint config
],
environment: [:]
)
]
}
}