Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to integrate SwiftLint with an iOS app using Swift Package Manager?

I'm creating a new iOS app in Xcode 11 (beta 5) and I'd like to try using Swift Package Manager instead of CocoaPods for managing dependencies.

A common pattern when using SwiftLint and CocoaPods is to add SwiftLint as a dependency and then add a build phase to execute ${PODS_ROOT}/SwiftLint/swiftlint; this way all developers end up using the same version of SwiftLint.

If I try to add SwiftLint as a SwiftPM dependency in Xcode, the executable target that I need is disabled:

Add Package Screenshot

I was able to fake it by creating a dummy Package.swift with no products or targets and running swift run swiftlint in my build phase, but it feels hacky and weird:

// 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: []
)

Is there a way do this without creating a dummy package? Or is Swift Package Manager just not the right tool for this particular use case?

like image 677
jjoelson Avatar asked Aug 12 '19 13:08

jjoelson


2 Answers

All methods of abusing iOS code dependency managers to run build tools are hacky and weird.

The correct way to version SPM-compliant tool dependencies is to use Mint: A package manager that installs and runs Swift CLI packages. See also Better iOS projects: How to manage your tooling with mint.

like image 107
Alex Curylo Avatar answered Sep 23 '22 19:09

Alex Curylo


I use xcodegen to genreate a Xcode project that has the ability to run scripts. This lets me see swiftlint warnings in Xcode while developing packages.

This tool creates a Xcode project from a project.yml definition. In that definition, you can add a script that runs swiftlint as a post compile task. Example.

Advantages of this method:

  • swiftlint warnings in Xcode.
  • Xcode settings beyond what SPM offers.

Disadvantages:

  • You rely on a third-party tool that could break or go away. However, you can drop this dependency at any time and go back to edit the Package.swift in Xcode.
  • You need to learn to write project.yml files.
  • If you use SPM bundles you need to generate the bundle accessor yourself.

A word about generating a bundle accessor. This is needed when working from a Xcode project because only SPM generates the file resource_bundle_accessor.swift to the project. If you already compiled after opening the Package.swift with Xcode, the file should be here:

find ~/Library/Developer/Xcode/DerivedData* -iname resource_bundle_accessor.swift

You can add it to the project, but if you are creating a framework, the bundle accessor can be as simple as:

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)
}
like image 45
Jano Avatar answered Sep 22 '22 19:09

Jano