PackageConfig

一个 Swift 包,允许你在 Package.swift 文件中定义配置设置——这样工具就可以将所有配置集中在一个地方。

工具开发者使用此依赖项来获取他们的配置设置。

包配置

在你的 Package.swift 文件中插入配置的最快方法是将 PackageConfig 添加到你的依赖项中

.package(url: "https://github.com/shibapm/PackageConfig.git", from: "0.13.0")

并将配置添加到你的 Package.swift 文件的底部

例如:

#if canImport(PackageConfig)
    import PackageConfig

    let config = PackageConfiguration([
        "komondor": [
            "pre-push": "swift test",
            "pre-commit": [
                "swift test",
                "swift run swiftformat .",
                "swift run swiftlint autocorrect --path Sources/",
                "git add .",
            ],
        ],
        "rocket": [
            "after": [
            	"push",
            ],
        ],
    ]).write()
#endif

自定义配置类型

PackageConfig 还提供了创建你自己的配置类型的可能性

用户需要输入:

运行这行命令来为你生成 PackageConfigs 目标的空源文件。

swift run package-config

第一次运行时,它应该返回一个错误 error: no target named 'PackageConfigs'

现在你可以像这样在 Package.swift 的目标列表中任何位置列出所有需要的包配置。

// PackageConfig parses PackageConfigs target in Package.swift to extract list of dylibs to link when compiling Package.swift with configurations
.target(name: "PackageConfigs", dependencies: [
    "ExampleConfig" // some executable configuration definition dylib
])

Package.swift 文件的最底部

#if canImport(ExampleConfig) // example config dynamic library
import ExampleConfig

// invoking write is mandatory, otherwise the config won't be written // thanks captain obvious
let exampleConfig = ExampleConfig(value: "example value").write()
#endif

如果多个依赖项使用 PackageConfig,请务必将它们各自包裹在

#if canImport(SomeLibraryConfig)
import SomeLibraryConfig

let someLibraryConfig = SomeLibraryConfig().write()
#endif

请务必调用 Configwrite 方法,否则这将无法工作。

然后,为了使用可执行文件,用户需要在与其项目 Package.swift 相同的目录中运行此命令

swift run package-config	# compiles PackageConfigs target, expecting to find a dylib in `.build` directory for each of the listed libraries configs
swift run example		# runs your library executable

工具开发者需要输入:

为了演示,假设你的库名为 Example,那么 Package.swift 文件会是这样的:

let package = Package(
    name: "Example",
    products: [
        // notice that product with your library config should be dynamic library in order to produce dylib and allow PackageConfig to link it when building Package.swift
        .library(name: "ExampleConfig", type: .dynamic, targets: ["ExampleConfig"]),
        // 
        .executable(name: "example", targets: ["Example"]),
    ],
    dependencies: [
        .package(url: "https://github.com/shibapm/PackageConfig.git", from: "0.0.2"),
    ],
    targets: [
        .target(name: "ExampleConfig", dependencies: ["PackageConfig"]),
        .target(name: "Example", dependencies: ["ExampleConfig"]),
    ]
)

在你的 ExampleConfig 目标中,按如下方式定义 ExampleConfig

import PackageConfig

// it must be public for you to use in your executable target
// also you must conform to `Codable` and `PackageConfig`
public struct ExampleConfig: Codable, PackageConfig {

    // here can be whatever you want as long as your config can stay `Codable`
    let value: String

   	// here you must define your config fileName which will be used to write and read it to/from temporary directory
    public static var fileName: String { return "example-config.json" }

    // public init is also a requirement
    public init(value: String) {
	self.value = value
    }
}

然后,例如在可执行的 Example 目标的 main.swift 文件中,你可以像这样加载你的配置:

import ExampleConfig

do {
    let config = try ExampleConfig.load()
    print(config)
} catch {
    print(error)
}

库开发者注意事项

由于 YourConfig 目标是一个动态库,你务必确保每次使用 PackageConfigreadwrite 方法时都已构建它。当从终端构建时,只需运行 swift build 即可完成此操作。


更新日志

工作原理

当你调用 YourPackage.load() 时,它将使用 swiftc 编译当前目录下的 Package.swift 文件。

在编译过程中,它将尝试链接在 PackageConfigs 目标中列出的动态库列表。

编译完成后,PackageConfig 将运行,并且当 YourPackage.write() 被调用时,你的包配置 JSON 将被写入临时目录。

之后,它将尝试读取 JSON 并将其解码,如同它是 YourPackage 类型,然后将其提供回你调用 load 方法的位置。

调试

如何查看 Package.swift 文件中的 JSON

使用 SPM 的 verbose 模式

~/d/p/o/i/s/PackageConfig  $ swift build --verbose

并获取第一个沙箱之后的内容。然后我将最后一个参数更改为 -fileno 1,它就打印了 JSON。

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc --driver-mode=swift -L /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/pm/4_2 -lPackageDescription -suppress-warnings -swift-version 4.2 -I /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/pm/4_2 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk /Users/ortatherox/dev/projects/orta/ios/spm/PackageConfig/Package.swift -fileno 1

{"errors": [], "package": {"cLanguageStandard": null, "cxxLanguageStandard": null, "dependencies": [], "name": "PackageConfig", "products": [{"name": "PackageConfig", "product_type": "library", "targets": ["PackageConfig"], "type": null}], "targets": [{"dependencies": [], "exclude": [], "name": "PackageConfig", "path": null, "publicHeadersPath": null, "sources": null, "type": "regular"}, {"dependencies": [{"name": "PackageConfig", "type": "byname"}], "exclude": [], "name": "PackageConfigTests", "path": null, "publicHeadersPath": null, "sources": null, "type": "test"}]}}

我如何验证它是否工作

我运行以下命令:

swift build; env DEBUG="*" swift run package-config-example

如果你不使用 fish

swift build; DEBUG="*" swift run package-config-example