Executable-Only Dependencies
Introduction
Executable-Only Dependencies would allow packages to be imported only for use in the package's development environment. Dependents of a package would not inherit the package's executable-only dependencies.
Motivation
CLI tools distributed through Swift Packages, such as linters or documentation generators, are currently imported as dependencies. Although these dependencies may only exist to use as an executable during development, the dependencies are shipped with the package. End-users of a package do not need to inherit development tools from the package.
This can encourage package developers to use more developer tools without frustrating end-users with unused dependencies.
Proposed solution
Introduce a new type of dependency .executable(...)
, where the parameter options are the same as .package(...)
. This distinguishes a package for executable-only. Executable-only packages can be used via CLI with swift run
, but can not be imported in code. In return, Executable-Only Dependencies are not passed on to dependents of the package.
E.g. If package A imports an executable-only linter, and if package B imports package A, package B does not inherit the linter as a dependency.
Detailed design
New types of dependencies:
extension Package.Dependency {
/// Adds an executable-only dependency that uses the version requirement,
/// starting with the given minimum version, going up to the next major version.
public static func executable(
name: String? = nil,
url: String,
from version: Version
) -> Package.Dependency
/// Adds a remote executable-only dependency with a given version requirement.
public static func executable(
name: String? = nil,
url: String,
_ requirement: Package.Dependency.Requirement
) -> Package.Dependency
/// Adds an executable-only dependency starting with a specific minimum
/// version, up to but not including a specified maximum version.
public static func executable(
name: String? = nil,
url: String,
_ range: Range<Version>
) -> Package.Dependency
/// Adds an executable-only dependency starting with a specific minimum
/// version, going up to and including a specific maximum version.
public static func executable(
name: String? = nil,
url: String,
_ range: ClosedRange<Version>
) -> Package.Dependency
/// Adds an executable-only dependency to a local package on the filesystem.
public static func executable(
name: String? = nil,
path: String
) -> Package.Dependency
}
Example use within Manifest:
dependencies: [
.executable(url: "https://github.com/Realm/SwiftLint", from: "0.28.1"),
]
Impact on existing packages
Existing packages won't be affected because executables can still be imported as regular packages.
Alternatives considered
Currently, developers can install executables through options like Homebrew. However, this requires additional setup for package developers to distribute the executable. Also, for packages with multiple developers, executables distributed outside of Swift Package Manager may vary between environments (the versions could be different, or not installed at all).
Follow up notes
This is my first post here, and I am not sure how exactly to move forward in the proposal process.
Any help is appreciated!
- Michael