[swift-evolution] [swift-build-dev] [Draft] Package Manager Manifest API Redesign
Ankit Aggarwal
ankit_aggarwal at apple.com
Wed Mar 1 03:14:29 CST 2017
Hi,
Thank you all for the feedback so far. I have updated the proposal:
https://github.com/aciidb0mb3r/swift-evolution/blob/manifest-api-redesign/proposals/xxxx-package-manager-manifest-api-redesign.md
The major changes are:
* Drop SystemPackageProvider struct upgrade.
* Drop the identity rule.
* Targets and Products will use factory methods.
* Rename VersionSetSpecifier to Requirement (because we also support
revision and branches and not just versions).
* Add a section on example manifests.
Note that there are collapsed examples and diffs in each proposed change.
Click "view example" to expand the examples.
On Wed, Mar 1, 2017 at 3:37 AM, Jens Nerup via swift-build-dev <
swift-build-dev at swift.org> wrote:
> Hi Daniel,
>
> Thanks for the reply. Sorry I wasn't clear - by removal I actually meant
> remove pkgConfig from the Package, and introduce it in a custom build
> configuration (associated with a Target). I think pkgConfig and custom
> build configurations may fit nicely together. And you are absolutely right
> this is probably best suited for a follow on to the current manifest API
> redesign. Let's discuss that later and once again thank you for your quick
> reply.
>
> Regards,
>
> Jens
>
> On 28 Feb 2017, at 17.05, Daniel Dunbar <daniel_dunbar at apple.com> wrote:
>
>
> On Feb 28, 2017, at 12:28 AM, Jens Nerup <jens at makecph.com> wrote:
>
> Hello Daniel,
>
> In general I’m really happy with the changes in the proposal and
> especially after you have incorporated the comments from David (Thanks
> David). In the proposal it is stated that the exclude section may be
> eliminated as soon as we have custom layouts. My question is: would
> pkgConfig be a candidate for removal as soon as we have support for custom
> build configurations?
>
>
> I don't think so, I don't think custom build configurations will be a
> replacement for the pkgConfig functionality, which is trying to gather
> settings from *outside* the package.
>
> I agree with the sentiment that it is an awkward thing to have the system
> module map package initializer, but unfortunately I think we may have to
> live with it for the time being. We have briefly discussed making it be a
> target not a package thing, and perhaps the move to using `.target()`
> should actually encourage us to do that, but that is probably something
> best done as a follow on to the manifest API redesign (as with exclude)
> given its limited scope.
>
> - Daniel
>
>
> Regards,
>
> Jens
>
> On 28 Feb 2017, at 01.50, Daniel Dunbar via swift-build-dev <
> swift-build-dev at swift.org> wrote:
>
> Hi David,
>
> We discussed the leading-dot & capitalization issue today again... this
> was already something we weren't really happy about, but had chosen to live
> with (using the "identity" rule to determine what was a type and what
> wasn't). However, as we talked it over more we:
> 1. Felt that for the product types, using .library vs .Library would be
> reasonable and consistent with a user model of thinking of these like enums
> (even though they won't actually be in practice, we will use factory
> functions on Product to make the dot work and keep the space extensible).
> 2. Realized that using .target would be a useful change to make now if we
> ever ended up needing to make the Targets array polymorphic (not something
> we plan to do now, but it never hurts to have it be extensible).
> so we decided to go ahead and revise to a model where we use leading-dot +
> lowercase for everything (except Package), including reverting
> SystemPackageProvider to the `.brew(...)` style syntax.
>
> Thanks for the feedback!
> - Daniel
>
> On Feb 27, 2017, at 2:21 AM, Ankit Aggarwal via swift-build-dev <
> swift-build-dev at swift.org> wrote:
>
> Hi David,
>
> Thanks for the feedback! Comments inline:
>
>
> On Sun, Feb 26, 2017 at 5:08 AM, David Hart via swift-build-dev <
> swift-build-dev at swift.org> wrote:
>
>> Was looking forward to this :) here are my comments:
>>
>> On 25 Feb 2017, at 01:35, Rick Ballard via swift-evolution <
>> swift-evolution at swift.org> wrote:
>>
>> Hi all,
>>
>> Ankit, Daniel, Anders, Boris and I have a draft proposal in progress for
>> a Package.swift manifest API redesign for the Package Manager. We'll
>> welcome comments or discussion at this time. My hope is that we can get
>> this polished up and ready for evolution within the next week or so, but
>> we'll see how the conversation goes!
>>
>> You can see the proposal in progress at https://github.com/aciidb0m
>> b3r/swift-evolution/blob/manifest-api-redesign/proposal
>> s/xxxx-package-manager-manifest-api-redesign.md. I'm also including the
>> current version inline in this email.
>>
>> Thanks,
>>
>> - Rick
>>
>> # Package Manager Manifest API Redesign
>>
>> * Proposal: [SE-XXXX](xxxx-package-manager-manifest-api-redesign.md)
>> * Author: [Ankit Aggarwal](https://github.com/aciidb0mb3r)
>> * Review Manager: TBD
>> * Status: **Discussion**
>>
>> ## Introduction
>>
>> This is a proposal for redesigning the `Package.swift` manifest APIs
>> provided
>> by Swift Package Manager.
>> This proposal only redesigns the existing public APIs and does not add any
>> new functionality; any API to be added for new functionality will happen
>> in
>> separate proposals.
>>
>> ## Motivation
>>
>> The `Package.swift` manifest APIs were designed prior to the [API Design
>> Guidelines] (https://swift.org/documentation/api-design-guidelines/),
>> and their
>> design was not reviewed by the evolution process. Additionally, there are
>> several small areas which can be cleaned up to make the overall API more
>> "Swifty".
>>
>> We would like to redesign these APIs as necessary to provide clean,
>> conventions-compliant APIs that we can rely on in the future. Because we
>> anticipate that the user community for the Swift Package Manager will grow
>> considerably in Swift 4, we would like to make these changes now, before
>> more packages are created using the old API.
>>
>> ## Proposed solution
>>
>> Note: Access modifier is omitted from the diffs and examples for brevity.
>> The
>> access modifier is `public` for all APIs unless specified.
>>
>> * Remove `successor()` and `predecessor()` from `Version`.
>>
>> These methods neither have well defined semantics nor are used a lot
>> (internally or publicly). For e.g., the current implementation of
>> `successor()` always just increases the patch version.
>>
>>
>> <details>
>> <summary>View diff</summary>
>> <p>
>> ```diff
>> struct Version {
>> - func successor() -> Version
>>
>> - func predecessor() -> Version
>> }
>> ```
>> </p></details>
>>
>> * Make all properties of `Package` and `Target` mutable.
>>
>> Currently, `Package` has three immutable and four mutable properties,
>> and
>> `Target` has one immutable and one mutable property. We propose to
>> make all
>> properties mutable to allow complex customization on the package object
>> after initial declaration.
>>
>> <details>
>> <summary>View diff and example</summary>
>> <p>
>>
>> Diff:
>> ```diff
>> final class Target {
>> - let name: String
>> + var name: String
>> }
>>
>> final class Package {
>> - let name: String
>> + var name: String
>>
>> - let pkgConfig: String?
>> + var pkgConfig: String?
>>
>> - let providers: [SystemPackageProvider]?
>> + var providers: [SystemPackageProvider]?
>> }
>> ```
>>
>> Example:
>> ```swift
>> let package = Package(
>> name: "FooPackage",
>> targets: [
>> Target(name: "Foo", dependencies: ["Bar"]),
>> ]
>> )
>>
>> #if os(Linux)
>> package.targets[0].dependencies = ["BarLinux"]
>> #endif
>> ```
>> </p></details>
>>
>> * Change `Target.Dependency` enum cases to lowerCamelCase.
>>
>> According to API design guidelines, everything other than types should
>> be in lowerCamelCase.
>>
>> <details>
>> <summary>View diff and example</summary>
>> <p>
>>
>> Diff:
>> ```diff
>> enum Dependency {
>> - case Target(name: String)
>> + case target(name: String)
>>
>> - case Product(name: String, package: String?)
>> + case product(name: String, package: String?)
>>
>> - case ByName(name: String)
>> + case byName(name: String)
>> }
>> ```
>>
>> Example:
>> ```diff
>> let package = Package(
>> name: "FooPackage",
>> targets: [
>> Target(
>> name: "Foo",
>> dependencies: [
>> - .Target(name: "Bar"),
>> + .target(name: "Bar"),
>>
>> - .Product(name: "SwiftyJSON", package: "SwiftyJSON"),
>> + .product(name: "SwiftyJSON", package: "SwiftyJSON"),
>> ]
>> ),
>> ]
>> )
>> ```
>> </p></details>
>>
>> * Add default parameter to the enum case `Target.Dependency.product`.
>>
>> The associated value `package` in the (enum) case `product`, is an
>> optional
>> `String`. It should have the default value `nil` so clients don't need
>> to
>> write it if they prefer using explicit enum cases but don't want to
>> specify
>> the package name i.e. it should be possible to write `.product(name:
>> "Foo")` instead of `.product(name: "Foo", package: nil)`.
>>
>> If
>> [SE-0155](https://github.com/apple/swift-evolution/blob/
>> master/proposals/0155-normalize-enum-case-representation.md)
>> is accepted, we can directly add a default value. Otherwise, we will
>> use a
>> static factory method to provide default value for `package`.
>>
>> * Upgrade `SystemPackageProvider` enum to a struct.
>>
>> This enum allows SwiftPM System Packages to emit hints in case of build
>> failures due to absence of a system package. Currently, only one system
>> package per system packager can be specified. We propose to allow
>> specifying multiple system packages by replacing the enum with this
>> struct:
>>
>> ```swift
>> public struct SystemPackageProvider {
>> enum PackageManager {
>> case apt
>> case brew
>> }
>>
>> /// The system package manager.
>> let packageManager: PackageManager
>>
>> /// The array of system packages.
>> let packages: [String]
>>
>> init(_ packageManager: PackageManager, packages: [String])
>> }
>> ```
>>
>> <details>
>> <summary>View diff and example</summary>
>> <p>
>>
>> Diff:
>> ```diff
>> -enum SystemPackageProvider {
>> - case Brew(String)
>> - case Apt(String)
>> -}
>>
>> +struct SystemPackageProvider {
>> + enum PackageManager {
>> + case apt
>> + case brew
>> + }
>> +
>> + /// The system package manager.
>> + let packageManager: PackageManager
>> +
>> + /// The array of system packages.
>> + let packages: [String]
>> +
>> + init(_ packageManager: PackageManager, packages: [String])
>> +}
>> ```
>>
>> Example:
>>
>> ```diff
>> let package = Package(
>> name: "Copenssl",
>> pkgConfig: "openssl",
>> providers: [
>> - .Brew("openssl"),
>> + SystemPackageProvider(.brew, packages: ["openssl"]),
>>
>> - .Apt("openssl-dev"),
>> + SystemPackageProvider(.apt, packages: ["openssl",
>> "libssl-dev"]),
>> ]
>> )
>> ```
>> </p></details>
>>
>>
>> Why not keep the enum and change the associated type to a String array?
>>
>>
> True, we could do that but we'd be repeating that information in every
> SystemPackager we add. Converting to a struct makes it easier to scale.
>
>
>> * Remove implicit target dependency rule for test targets.
>>
>> There is an implicit test target dependency rule: a test target
>> "FooTests"
>> implicity depends on a target "Foo", if "Foo" exists and "FooTests"
>> doesn't
>> explicitly declare any dependency. We propose to remove this rule
>> because:
>>
>> 1. It is a non obvious "magic" rule that has to be learned.
>> 2. It is not possible for "FooTests" to remove dependency on "Foo"
>> while
>> having no other (target) dependency.
>> 3. It makes real dependencies less discoverable.
>> 4. It may cause issues when we get support for mechanically editing
>> target
>> dependencies.
>>
>> * Introduce an "identity rule" to determine if an API should use an
>> initializer
>> or a factory method:
>>
>>
>> Could you explain this rule in more detail. What is an identity in this
>> case? I'm confused.
>>
>
>
> This is similar to the rule we use to decide if something should be a
> struct or a class. If you're forming a concrete object, that would be an
> identity. Consider these two examples:
>
> 1. Target and its dependencies:
>
> Target(name: "Foo", dependencies: [.target(name: "Bar")])
>
> Here the target Foo is being constructed, so an initializer is used. The
> target Bar is being referred in Foo's dependencies so that uses a factory
> method.
>
> 2. Product and product dependencies in targets:
>
> When constructing the product, the initializer should be used:
> .Library(name: "FooLib", targets: ["Foo", "Utility"])
>
> And while referring to the product, like in target dependency, factory
> method should be used:
> Target(name: "Foo", dependencies: [.product(name: "FooLib")])
>
>
>> Under this rule, an entity having an identity, will use a type
>> initializer
>> and everything else will use factory methods. `Package`, `Target` and
>> `Product` are identities. However, a product referenced in a target
>> dependency is not an identity.
>>
>> This means the `Product` enum should be converted into an identity. We
>> propose to introduce a `Product` class with two subclasses:
>> `Executable`
>> and `Library`. These subclasses will be nested inside `Product` class
>> instead of being a top level declaration in the module. The major
>> advantage of nesting is that we get a namespace for products and it is
>> easy
>> to find all the supported products when the product types grows to a
>> large
>> number. A downside of nesting is that the product initializers will
>> have to
>> used with the dot notation (e.g.: `.Executable(name: "tool", targets:
>> ["tool"])`) which is a little awkward because we expect factory
>> methods to
>> use the dots.
>>
>> They will be defined as follow:
>>
>> ```swift
>> /// Represents a product.
>> class Product {
>>
>> /// The name of the product.
>> let name: String
>>
>> /// The names of the targets in this product.
>> let targets: [String]
>>
>> private init(name: String, targets: [String]) {
>> self.name = name
>> self.targets = targets
>> }
>>
>> /// Represents an executable product.
>> final class Executable: Product {
>>
>> /// Creates an executable product with given name and targets.
>> override init(name: String, targets: [String])
>> }
>>
>> /// Represents a library product.
>> final class Library: Product {
>> /// The type of library product.
>> enum LibraryType: String {
>> case `static`
>> case `dynamic`
>> }
>>
>> /// The type of the library.
>> ///
>> /// If the type is unspecified, package manager will
>> automatically choose a type.
>> let type: LibraryType?
>>
>> /// Creates a library product.
>> init(name: String, type: LibraryType? = nil, targets: [String])
>> }
>> }
>> ```
>>
>> <details>
>> <summary>View example</summary>
>> <p>
>>
>> Example:
>>
>> ```swift
>> let package = Package(
>> name: "Foo",
>> target: [
>> Target(name: "Foo", dependencies: ["Utility"]),
>> Target(name: "tool", dependencies: ["Foo"]),
>> ],
>> products: [
>> .Executable(name: "tool", targets: ["tool"]),
>> .Library(name: "Foo", targets: ["Foo"]),
>> .Library(name: "FooDy", type: .dynamic, targets: ["Foo"]),
>> ]
>> )
>> ```
>> </p></details>
>>
>>
>> This API looks very weird: the leading dog is usually used for enum cases
>> and static members. Using it with a type means that the capitalization
>> looks very out of place.
>>
>>
> Yes, as mentioned in the proposal we think the dot and capitalization
> following it looks out of place here but we really think that the products
> should be under a namespace because the types supported product might grow
> to a substantial number in future. Adding namespace using nesting solves
> this issue nicely.
>
> Another advantage would be getting free autocomplete support for products
> in IDEs or text editors which supports SourceKit. Right now there is none
> which supports autocomplete for the manifest file but since SourceKit is
> cross platform, it should be possible to create a plugin in future.
>
>
>> * Special syntax for version initializers.
>>
>> A simplified summary of what is commonly supported in other package
>> managers:
>>
>> | Package Manager | x-ranges | tilde (`~` or `~>`) | caret
>> (`^`) |
>> |-----------------|---------------|----------------------
>> ---|---------------|
>> | npm | Supported | Allows patch-level changes if a
>> minor version is specified on the comparator. Allows minor-level changes if
>> not. | patch and minor updates |
>> | Cargo | Supported | Same as above | Same as
>> above |
>> | CocoaPods | Not supported | Same as above | Not
>> supported |
>> | Carthage | Not supported | patch and minor updates | Not
>> supported |
>>
>> Some general observations:
>>
>> * Every package manager we looked at for this supports the tilde `~`
>> operator in some form.
>> * The widely accepted suggestion on how to constrain your versions is
>> "use
>> `~>`, it does the right thing".
>> * It's not clear to us why this has so much traction as "the right
>> thing", as it can
>> prevent upgrades that should be compatible (one minor version to
>> next minor version).
>> * Most users may not really understand `~`, and just use it per
>> recommendations.
>> See e.g. how Google created a [6-minute instructional video](
>> https://www.youtube.com/watch?v=x4ARXyovvPc)
>> about this operator for CocoaPods.
>> * A lot of people even explicitly set a single exact version simply
>> because
>> they don't know better. This leads to "dependency hell"
>> (unresolvable dependencies
>> due to conflicting requirements for a package in the dependency
>> graph).
>> * The Swift Package Manager will probably have many novice users,
>> because it
>> comes built-in to Swift.
>> * We think caret `^` has the right behaviour most of the time. That
>> is, you
>> should be able to specify a minimum version, and you should be
>> willing to let
>> your package use anything after that up to the next major version.
>> This policy
>> works if packages correctly follow semantic versioning, and it
>> prevents "dependency
>> hell" by expressing permissive constraints.
>> * We also think caret `^` is syntactically non-obvious, and we'd
>> prefer a syntax
>> that doesn't require reading a manual for novices to understand,
>> even if that
>> means we break with the syntactic convention established by the
>> other package managers which
>> support caret `^`.
>> * We'd like a convenient syntax for caret `^`, but to still support
>> the use
>> case that tilde `~` is used for; but tilde `~` (or a single exact
>> version) should
>> be less convenient than caret `^`, to encourge permissive dependency
>> constraints.
>>
>> What we propose:
>>
>> * We will introduce a factory method which takes a lower bound version
>> and
>> forms a range that goes upto the next major version (i.e. caret).
>>
>> ```swift
>> // 1.0.0 ..< 2.0.0
>> .package(url: "/SwiftyJSON", from: "1.0.0"),
>>
>> // 1.2.0 ..< 2.0.0
>> .package(url: "/SwiftyJSON", from: "1.2.0"),
>>
>> // 1.5.8 ..< 2.0.0
>> .package(url: "/SwiftyJSON", from: "1.5.8"),
>> ```
>>
>> * We will introduce a factory method which takes
>> `VersionSetSpecifier`, to
>> conveniently specify common ranges.
>>
>> `VersionSetSpecifier` is an enum defined as follows:
>>
>> ```swift
>> enum VersionSetSpecifier {
>> case exact(Version)
>> case range(Range<Version>)
>>
>> /// Creates a specifier for an exact version.
>> static func only(_ version: Version) -> VersionSetSpecifier
>>
>> /// Creates a specified for a range starting at the given lower
>> bound
>> /// and going upto next major version.
>> static func uptoNextMajor(_ version: Version) ->
>> VersionSetSpecifier
>>
>> /// Creates a specified for a range starting at the given lower
>> bound
>> /// and going upto next minor version.
>> static func uptoNextMinor(_ version: Version) ->
>> VersionSetSpecifier
>> }
>> ```
>>
>> Examples:
>>
>> ```swift
>> // 1.5.8 ..< 2.0.0
>> .package(url: "/SwiftyJSON", .uptoNextMajor("1.5.8")),
>>
>> // 1.5.8 ..< 1.6.0
>> .package(url: "/SwiftyJSON", .uptoNextMinor("1.5.8")),
>>
>> // 1.5.8
>> .package(url: "/SwiftyJSON", .only("1.5.8")),
>> ```
>>
>> * This will also give us ability to add more complex features in
>> future:
>>
>> Examples:
>>
>> Note that we're not actually proposing these as part of this proposal.
>>
>>
>> ```swift
>> .package(url: "/SwiftyJSON", .uptoNextMajor("1.5.8").exclud
>> ing("1.6.4")),
>>
>> .package(url: "/SwiftyJSON", .only("1.5.8", "1.6.3")),
>>
>> ```
>>
>> * We will introduce a factory method which takes `Range<Version>`, to
>> specify
>> arbitrary open range.
>>
>> ```swift
>> // Constraint to an arbitrary open range.
>> .package(url: "/SwiftyJSON", "1.2.3"..<"1.2.6"),
>> ```
>>
>> * We will introduce a factory method which takes
>> `ClosedRange<Version>`, to specify
>> arbitrary closed range.
>>
>> ```swift
>> // Constraint to an arbitrary closed range.
>> .package(url: "/SwiftyJSON", "1.2.3"..."1.2.8"),
>> ```
>>
>> * We will remove all of the current factory methods:
>>
>> ```swift
>> // Constraint to a major version.
>> .Package(url: "/SwiftyJSON", majorVersion: 1),
>>
>> // Constraint to a major and minor version.
>> .Package(url: "/SwiftyJSON", majorVersion: 1, minor: 2),
>>
>> // Constraint to an exact version.
>> .Package(url: "/SwiftyJSON", "1.2.3"),
>>
>> // Constraint to an arbitrary range.
>> .Package(url: "/SwiftyJSON", versions: "1.2.3"..<"1.2.6"),
>>
>> // Constraint to an arbitrary closed range.
>> .Package(url: "/SwiftyJSON", versions: "1.2.3"..."1.2.8"),
>> ```
>>
>>
>> I'm ver happy with the versioning part of this proposal :-)
>>
>>
> Great!
>
>> * Adjust order of parameters on `Package` class:
>>
>> We propose to reorder the parameters of `Package` class to: `name`,
>> `pkgConfig`, `products`, `dependencies`, `targets`,
>> `compatibleSwiftVersions`.
>>
>> The rationale behind this reorder is that the most interesting parts
>> of a
>> package are its product and dependencies, so they should be at the top.
>> Targets are usually important during development of the package.
>> Placing
>> them at the end keeps it easier for the developer to jump to end of the
>> file to access them. Note that the compatibleSwiftVersions property
>> will likely
>> be removed once we support Build Settings, but that will be discussed
>> in a separate proposal.
>>
>>
>> I would have liked this proposal to suggest modifying the API so the
>> order is insignificant. While ordering feels important for me when calling
>> a function or initializer with few arguments (like .package(url: "", from:
>> "1.4.5")), the arguments to the Package function seem like a list of
>> configuration options and shouldn't have a fixed order. My suggestion was
>> to remove all arguments but the name and adds a configuration closure:
>>
>> let package = Package(name: "paper") {
>> $0.products = [...]
>> $0.dependencies = [...]
>> }
>>
>>
> It will be possible to avoid using the initializer because all the
> properties will be made mutable. However I think if majority of packages
> uses the initializer and thus have a consistent ordering, it will be easier
> for other developers to read manifests on Github (or similar).
>
> PS: The closure syntax can also be added using extension in the manifest
> itself if someone really wants to use it.
>
>
>> <details>
>> <summary>View example</summary>
>> <p>
>>
>> Example:
>>
>> ```swift
>> let package = Package(
>> name: "Paper",
>> products: [
>> .Executable(name: "tool", targets: ["tool"]),
>> .Libary(name: "Paper", type: .static, targets: ["Paper"]),
>> .Libary(name: "PaperDy", type: .dynamic, targets: ["Paper"]),
>> ],
>> dependencies: [
>> .package(url: "http://github.com/SwiftyJSON", from: "1.2.3"),
>> .package(url: "../CHTTPParser", .uptoNextMinor("2.2.0")),
>> .package(url: "http://some/other/lib", .only("1.2.3")),
>> ]
>> targets: [
>> Target(
>> name: "tool",
>> dependencies: [
>> "Paper",
>> "SwiftyJSON"
>> ]),
>> Target(
>> name: "Paper",
>> dependencies: [
>> "Basic",
>> .target(name: "Utility"),
>> .product(name: "CHTTPParser"),
>> ])
>> ]
>> )
>> ```
>> </p></details>
>>
>> * Eliminate exclude in future (via custom layouts feature).
>>
>> We expect to remove the `exclude` property after we get support for
>> custom
>> layouts. The exact details will be in the proposal of that feature.
>>
>> ## Impact on existing code
>>
>> The above changes will be implemented only in the new Package Description
>> v4
>> library. The v4 runtime library will release with Swift 4 and packages
>> will be
>> able to opt-in into it as described by
>> [SE-0152](https://github.com/apple/swift-evolution/blob/mast
>> er/proposals/0152-package-manager-tools-version.md).
>>
>> There will be no automatic migration feature for updating the manifests
>> from v3
>> to v4. To indicate the replacements of old APIs, we will annotate them
>> using
>> the `@unavailable` attribute where possible. Unfortunately, this will not
>> cover
>> all the changes for e.g. rename of the target dependency enum cases.
>>
>> All new packages created with `swift package init` command in Swift 4
>> tools
>> will by default to use the v4 manifest. It will be possible to switch to
>> v3
>> manifest version by changing the tools version using `swift package
>> tools-version --set 3.1`. However, the manifest will needed to be
>> adjusted to
>> use the older APIs manually.
>>
>> Unless declared in the manifest, existing packages automatically default
>> to the Swift 3 minimum tools version; since the Swift 4 tools will also
>> include
>> the v3 manifest API, they will build as expected.
>>
>> A package which needs to support both Swift 3 and Swift 4 tools will need
>> to
>> stay on the v3 manifest API and support the Swift 3 language version for
>> its
>> sources, using the API described in the proposal
>> [SE-0151](https://github.com/apple/swift-evolution/blob/mast
>> er/proposals/0151-package-manager-swift-language-compatibility-version.md
>> ).
>>
>> An existing package which wants to use the new v4 manifest APIs will need
>> to bump its
>> minimum tools version to 4.0 or later using the command `$ swift package
>> tools-version
>> --set-current`, and then modify the manifest file with the changes
>> described in
>> this proposal.
>>
>> ## Alternatives considered
>>
>> * Add variadic overloads.
>>
>> Adding variadic overload allows omitting parenthesis which leads to
>> less
>> cognitive load on eyes, especially when there is only one value which
>> needs
>> to be specified. For e.g.:
>>
>> Target(name: "Foo", dependencies: "Bar")
>>
>> might looked better than:
>>
>> Target(name: "Foo", dependencies: ["Bar"])
>>
>> However, plurals words like `dependencies` and `targets` imply a
>> collection
>> which implies brackets. It also makes the grammar wrong. Therefore, we
>> reject this option.
>>
>> * Version exclusion.
>>
>> It is not uncommon to have a specific package version break something,
>> and
>> it is undesirable to "fix" this by adjusting the range to exclude it
>> because this overly constrains the graph and can prevent picking up the
>> version with the fix.
>>
>> This is desirable but it should be proposed separately.
>>
>> * Inline package declaration.
>>
>> We should probably support declaring a package dependency anywhere we
>> support spelling a package name. It is very common to only have one
>> target
>> require a dependency, and annoying to have to specify the name twice.
>>
>> This is desirable but it should be proposed separately.
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>>
>> One thing that still really bothers me about the API is the inconsistency
>> in leading dots and capitalization. Should a novice (or an expert) have to
>> remember the following different writings:
>>
>> Target(name: "Foo", dependencies: ["Utility"])
>> .package(url: "http://github.com/SwiftyJSON", from: "1.2.3")
>> .Library(name: "Paper", type: .static, targets: ["Paper"])
>>
>> I understand the arguments brought forward in the proposal. But from a
>> package author point of view, it's not obvious why Target is capitalized,
>> why package is lowercase with a leading dot and why Library is capitalized
>> with a leading dot. It looks confusing and inconsistent, which makes it
>> less pleasant to read and harder to remember.
>>
>> Could we push for more consistency by having everything b lowercased with
>> a leading dot? It does force us to introduce a Target factory method, to
>> revert SystemPackageProvider back to an enum, to revert products back to an
>> enum. But I think it's worth it.
>>
>
> It is true that it might not be obvious when to use what initially, but we
> think this is a good rule to create a distinction between constructing
> things and referring to things. A downside of lowercasing everything would
> be: it might seem like the references support all the parameters that
> constructor supports. e.g. .target(name: "Foo", dependencies: [
> .target(name: "Bar", dependencies: ["Baz"]) ])
>
>
>
>
>
>
> _______________________________________________
> swift-build-dev mailing list
> swift-build-dev at swift.org
> https://lists.swift.org/mailman/listinfo/swift-build-dev
>
>
> _______________________________________________
> swift-build-dev mailing list
> swift-build-dev at swift.org
> https://lists.swift.org/mailman/listinfo/swift-build-dev
>
>
>
>
> _______________________________________________
> swift-build-dev mailing list
> swift-build-dev at swift.org
> https://lists.swift.org/mailman/listinfo/swift-build-dev
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170301/46ba655c/attachment.html>
More information about the swift-evolution
mailing list