I want to create my own package manager, and currently reviewing existing solutions.
I'm playing with PHP's Composer now, and it was quite surprising that it has two files:
composer.json
for project configuration, and non-pinned dependencies
composer.lock
for exact pinned dependencies
I do understand why one needs to pin dependencies, .lock
information by itself seems logical to me.
What I do not understand is why project metadata was split into two files.
Can anyone explain, why it was designed this way? Why deps could not be pinned right in the composer.json
?
UPD. Turns out, Rust's Cargo has the same two file configuration in place, and has a nice explanation of the meaning of the .lock
file: http://doc.crates.io/guide.html#cargotoml-vs-cargolock
.lock
information is absolutely pinned, typically created by a composer update
request based on the json
information... but developers don't necessarily want to pin everything to an exact version, and without that .json
file they have to upgrade the .lock
file manually for every version upgrade of their dependencies.
The .lock
also holds dependencies of dependencies, and dependencies of dependencies of dependencies, etc... whereas the .json
file only holds immediate dependencies.... and as a developer, you should only need to control your immediate dependencies, and allow those libraries to control their own dependencies via their own .json
files
Basically, you should build your application against the json
but deploy against the .lock
During development, you usually want to be able to upgrade to the latest compatible version of dependencies easily. composer.json
has the information on what the dependencies are and which versions are compatible. composer.lock
lacks the compatibility information, it may say that the package was built against version 2.2.7 of a dependency but information is missing about rules such as that versions >= 2.1 and < 3 of that dependency are compatible while lower versions aren't and the next major version isn't guaranteed to be so play it safe.
When building for testing or release, on the other hand, it's necessary to make sure you build against the exact same set of dependency versions every time. composer.lock
allows that by listing out the exact versions used. Even if new versions of dependencies come out, the dependency pinning insures that the build won't change so you won't have to worry about changes in behavior caused by changes in dependency packages.