[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