<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Dec 22, 2015, at 3:24 PM, Paul Cantrell &lt;<a href="mailto:cantrell@pobox.com" class="">cantrell@pobox.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">I share Rick’s concerns about any proposal that pushes locked versions downstream to dependent projects. Two thoughts on that:</div><div class=""><br class=""></div><div class="">First, the specific: a lockfile should lock the versions for <i class="">all</i> 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.)</div></div></div></blockquote><div><br class=""></div>Indeed, if the proposal is not clear here, it should be.<br class=""><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Second, some general thoughts on the principles underlying that, which also address the concern about multiple sources of truth:</div><div class=""><br class=""></div><div class="">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.”</div><div class=""><br class=""></div><div class="">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&nbsp;<i class="">may</i> happen; the lockfile describes what <i class="">did</i> happen.</div><div class=""><br class=""></div><div class="">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.</div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>– `swift build --update-deps` updates all dependencies to the latest allowed version and sets/updates dependency locks for each dependency.</div><div class=""><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>– `swift build --update-dep=&lt;package name&gt;` updates the named dependency to the latest allowed version and sets/updates dependency lock for that dependency.</div></div></div></blockquote></div><div class=""><div class=""><blockquote type="cite" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>– `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.</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>– `swift build --lock-dep=&lt;package name&gt; looks at HEAD of the cloned named dependency and sets the dependency lock in the the top-level Package.swift for that one dependency.</div><div class=""></div></div></blockquote></div></div><div class=""><br class=""></div><div class="">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?</div></div></div></blockquote><div><br class=""></div><div>Yes. The user has the capability of eg. specifying a branch. Package.swift cannot do this, but the lock file can override it.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">That particular command line syntax is a bit Byzantine. I suspect I’d be Googling it a lot.</div></div></div></blockquote><div><br class=""></div><div>I think it can be simplified. Dropping the -dep suffix alone makes it more conventional.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">I’m not so sure “build” makes sense as the top-level command. What about (just brainstorming):</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>swift package update</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>swift package update &lt;Lib&gt;</div><div class=""><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>swift package lock</div></div><div class=""><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>swift package lock &lt;Lib&gt;</div></div><div class=""><br class=""></div><div class="">…or maybe “deps” instead of “package”?</div></div></div></blockquote><div><br class=""></div><div>`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.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><blockquote type="cite" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">– 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.</div></div></blockquote></div><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><br class=""></div></div></div><div class="">I would imagine that…</div><div class=""><div class=""><br class=""></div><div class="">• Package.swift can specify any tag or branch, not just a version number.</div></div></div></div></blockquote><div><br class=""></div><div>This is not intended by this proposal. Just versions.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class="">• The update and lock commands write&nbsp;a specific commit to the lock file.</div></div></div></div></blockquote><div><br class=""></div><div>Yes.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class="">• 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.</div></div></div></div></blockquote><div><br class=""></div><div>Has value.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><blockquote type="cite" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">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.</div></div></blockquote></div><div class=""><br class=""></div><div class="">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.</div></div></div></blockquote><br class=""></div><div>Package.swift cannot specify a branch in this proposal.</div><br class=""></body></html>