[swift-build-dev] [swift-evolution] [Proposal] Lock file for Swift Package Manager

Max Howell max.howell at apple.com
Tue Dec 22 14:41:10 CST 2015

> On Dec 22, 2015, at 3:24 PM, Paul Cantrell <cantrell at pobox.com> wrote:
> I share Rick’s concerns about any proposal that pushes locked versions downstream to dependent projects. Two thoughts on that:
> First, the specific: a lockfile should lock the versions for all dependencies, direct and indirect. Library lockfiles should have no effect on downstream projects. (Bundler does it this way, and it plays out well in practice.)

Indeed, if the proposal is not clear here, it should be.

> Second, some general thoughts on the principles underlying that, which also address the concern about multiple sources of truth:
> The dependency specification (Package.swift) and the lockfile serve distinct roles. The dependency spec says “here’s information about what I need, and which versions I think I’m compatible with.” The lockfile says “here are the specific versions I’m actually using to build and test with.”
> In short, Package.swift is a declaration of intent, whereas the lockfile is a statement of fact. Package.swift is a set of constraints; the lockfile is a snapshot. Package.swift describes things what may happen; the lockfile describes what did happen.
> The lockfile’s primary purposes are (1) to prevent external variables from causing surprising breakages, and (2) to diagnose the “it works here but not there” problem. This is why lockfiles should be checked in, but shouldn’t affect downstream projects.
>> 	– `swift build --update-deps` updates all dependencies to the latest allowed version and sets/updates dependency locks for each dependency.
>> 	– `swift build --update-dep=<package name>` updates the named dependency to the latest allowed version and sets/updates dependency lock for that dependency.
>> 	– `swift build --lock-deps` looks at the HEAD of all cloned dependencies and sets the dependency lock in the top-level Package.swift to that HEAD commit. This is useful when you want to explicitly lock to something other than the latest allowed version of a package.
>> 	– `swift build --lock-dep=<package name> looks at HEAD of the cloned named dependency and sets the dependency lock in the the top-level Package.swift for that one dependency.
> This set of capabilities seems right, though I’m not entirely sure about the separate “lock” operation. Are you thinking of the case when somebody manually checks out a different version in a submodule, totally bypassing the package manager?

Yes. The user has the capability of eg. specifying a branch. Package.swift cannot do this, but the lock file can override it.

> That particular command line syntax is a bit Byzantine. I suspect I’d be Googling it a lot.

I think it can be simplified. Dropping the -dep suffix alone makes it more conventional.

> I’m not so sure “build” makes sense as the top-level command. What about (just brainstorming):
> 	swift package update
> 	swift package update <Lib>
> 	swift package lock
> 	swift package lock <Lib>
> …or maybe “deps” instead of “package”?

`swift build` is already the command, we could at a later time split the switches out into new sub commands of the swift multitool, but that would be another later proposal after more functionality is available and we understand the overall UX for the CLI command better.

>> – This proposal still doesn't fully address how you can use a branch for your dependency instead of a version tag, which was one of the reasons this topic came up in the first place. You could do so by checking out the branch in your cloned dependency and then using `swift build --lock-deps` to lock to that commit, but if you do a `swift build --update-deps` we'll blow that away.
> I would imagine that…
> • Package.swift can specify any tag or branch, not just a version number.

This is not intended by this proposal. Just versions.

> • The update and lock commands write a specific commit to the lock file.


> • Perhaps, for readability, if there is a tag for the commit, the tag name goes in the lockfile instead of a raw commit hash, and that tag name might be a version number — but it’s always specific commits in the lock file.

Has value.

>> To solve this, perhaps a dependency lock could have an additional optional "overridingRef" property which, if specified, overrides the version specifier for the package. That means that `swift build --update-deps` will now update the package to what that ref points to. The --lock-dep option could allow a follow-on option --lock-overriding-ref which takes the overriding ref to set.
> That seems overly complex at first glance. If Package.swift does specify a branch, I interpret that as saying, “I depend on prerelease features of this package. Resolve dependencies at your own risk!” At that point, having a version number in there as well is just confusion. When the code on that branch gets release, you go back to the version specifier.

Package.swift cannot specify a branch in this proposal.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-build-dev/attachments/20151222/1f55da99/attachment.html>

More information about the swift-build-dev mailing list