-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New 2.0 lockfiles #34
Conversation
This seems like a great proposal.
Does this mean we can model and lock hidden requirements as "build" requires? (e.g. for an auxiliary binary package)
Doesn't this contradict "Lockfiles will no longer contain information about profiles, settings, options"?
Perfect 👍 |
I am a little bit sad that you want to remove profile/option infos from the lockfiles syncing profiles to developer machines can be also pain-point. In fact, my additional wish would have been to even add the enabled remotes into lockfiles, with this proposal, it seems, my wish is gone for ever, and I wonder, if this will not have some negative impact to reproducibility or will require additional work on project site |
design/034-new_lockfiles.md
Outdated
- Lockfiles will no longer contain information about profiles, settings, options (as they did in 1.X) | ||
- Lockfiles will not contain information about the dependency graph, only ordered lists (ordered by version and revision timestamp) of package references. | ||
- The default level of locking will be locking down to the recipe reference, that is, including the version and the recipe revision (``pkg/version@user/channel#recipe_revision``), but not the package-id nor the package-revision. This is aligned with the previously accepted Tribe proposal of removing the [``package_revision_mode``](https://github.com/conan-io/tribe/pull/30). Even if implementing lockfiles locking down the package revision will be possible, that will be considered the exception, and the main flows, documentation and behavior will be optimized for locking down to the recipe revision. | ||
- Locking by default will be non-strict, that is, if some ``requires`` cannot find a matching locked version in the lockfile, it will be resolved normally. A ``--lockfile-strict`` mode will be implemented, but not the default, to enforce finding a match for declared requires in the lockfile or failing otherwise. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't quite understand this one. Isn't the whole purpose of lockfiles to be strict and prevent any changes such as overrides?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strict enforcement of the lock is most likely the single most reported issue in our support, and the origin of many frustrations. Recall that many operations imply in many occasions that it cannot be strict:
- Capturing a lockfile for every configuration after the first one, when the first lockfile from the first configuration is provided, to guarantee it is as consistent as possible between configurations. So if we have to capture a lockfile for N configurations, that means that N-1
conan lock create
commands will have to add--lockfile-no-strict
- Every change that every developer does to a package, can potentially change the dependencies. Add a new one, update the version of a existing one, etc. This is a very common operation in the day-to-day. This also requires
--lockfile-no-strict
otherwise each developer change torequires
will raise an error. - Application of a lockfile created with
conan lock add
to lock only some of the dependencies or transitive dependencies will also require--lockfile-no-strict
, always, by definition. - The application of a partial lockfile, like the one used to build the changes done to a package in the middle of the graph, when we want to apply it to a downstream consumer application, will also require
--lockfile-no-strict
, always, by definition
One of the first implementation we had was the other way around, strict by default. When we realized that we were basically either saying strict=False
in code (for some commands), or passing --lockfile-no-strict
in the command line for the majority of command lines we had in our testing and examples (note that we have been working in more elaborte examples like conan-io/examples2#7, to further learn and evaluate this proposal), we decided to change the default.
Note that being non-strict doesn't mean that it will not lock things correctly. Whatever was locked will be correctly locked, unless the developer explicitly wanted to change dependencies outside of that lock. Lockfiles will prevent against any changes in the dependencies, if new versions or revisions are published. They never intended to be (and they are not in other language package managers) a mechanism to block developers to do modifications to source and recipes, and this was probably the root source of the above mentioned frustrations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My intuition tells me that lockfiles should be honored 100% of the times to ensure reproducible builds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand correctly:
- If a package is referenced in the conanfile (or in some dependency in the graph) and something that matches that portion of the reference is found in the lockfile, the behavior is the same in strict and non-strict mode: the package used will match what is in the lockfile. In other words, for packages found in the lockfile, the lockfile is respected.
- If a package is referenced in the conanfile (or in some dependency in the graph) and something that matches that portion of the reference is NOT found in the lockfile, in strict mode the operation will fail, and in non-strict mode it will fall back to using normal conan package lookup mechanisms.
Is this a correct interpretation @memsharded ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, perfect interpretation.
And this is the reason why at the moment we have proposed to be "non-strict" by default. If there is something in the conanfile
that is not in the lockfile
is because the users did a change to it, or is using just a partial lockfile or something like that, that is, because the user want that. Lockfiles are not a mechanism to prevent users doing changes to the graph, is a mechanism to avoid new published versions or revisions to affect users that didn't change their conanfiles, without them being able to control or block that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In light of that, would a conditional default for lockfile strictness make sense? For example:
- If
--lockfile-out
is on the command line, default to non-strict mode. - If
--lockfile
is on the command line without--lockfile-out
, default to strict mode.
Specifying --lockfile-out
indicates that the user wants to generate a lockfile
with new information, so non-struct makes sense. If no new lockfile
is being generated, then strict may be a sane default as it is only consuming a lockfile and not writing a new one.
- The default level of locking will be locking down to the recipe reference, that is, including the version and the recipe revision (``pkg/version@user/channel#recipe_revision``), but not the package-id nor the package-revision. This is aligned with the previously accepted Tribe proposal of removing the [``package_revision_mode``](https://github.com/conan-io/tribe/pull/30). Even if implementing lockfiles locking down the package revision will be possible, that will be considered the exception, and the main flows, documentation and behavior will be optimized for locking down to the recipe revision. | ||
- Locking by default will be non-strict, that is, if some ``requires`` cannot find a matching locked version in the lockfile, it will be resolved normally. A ``--lockfile-strict`` mode will be implemented, but not the default, to enforce finding a match for declared requires in the lockfile or failing otherwise. | ||
- A single lockfile file can lock multiple configurations, for different OS, compilers, build-types, etc., as long as they belong to the same graph. Lockfiles can be constructed for these multiple configurations incrementally, or they can be merged later. The concept of “lockfile bundles” will no longer be necessary | ||
- Lockfiles will not be a version definition mechanism, they need to be a “realizable” snapshot of a dependency graph that should be able to be evaluated in the first place. However, they will allow their usage to define overrides or definitions of versions or recipe revisions that will be used if they fit in the valid definition of the original ``requires`` (that is, if the version fits in the version range of the recipe ``requires``, or always for recipe revisions) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, basically, this is then the same as raw conanfile that does not use version ranges?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it will at least also include the recipe_revision
, which is very rarely included explicitly in conanfiles.
In this specific point, lockfiles don't deviate much of what they already do in 1.X. They are still "snapshots" of a real dependency graph, a specific instance in time of the recipes requires
resolved to some specific values. But they cannot define a reality that cannot be produced by recipes in the first place.
design/034-new_lockfiles.md
Outdated
conan install . --lockfile=conan.lock # will work | ||
``` | ||
|
||
Will not fail by default, and will be able to resolve to ``pkg1.1``. This is because the default mode is non-strict. One of the most frustrating behaviors of Conan 1.X lockfiles was when lockfiles didn’t allow you to do modifications to your conanfiles and keep working. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This itches me a bit. It means that the final resolved graph will be different than the one written in the conanfile.
If the installation fails here, it would immediately inform the developer that it has got a stale lockfile.
However, another option would be for this to automatically update the lockfile, so at least a diff would be seen during the committing to VCS.
It would be a really bad experience if you think that one state (i.e. the one from the lockfile) will be after issuing conan install ...
and you end up with a totally different state, without knowing what happened (i.e. conanfile having precedence over lockfile).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this has been elaborated in the above response: #34 (comment)
It is not possible to get to a different state using a lockfile, and the same starting point, lets say a given conanfile.txt
. The different is if the conanfile.txt
gets some changes that are no longer resolvable against the lockfile. As this happens to be an operation that happens very often in development, and users were frustrated about it raising an error, we made it non-strict as default. Of course if you want to get guarantees that this doesn't happen, that is the reason why --lockfile-strict
is there, which you can always opt-in in CI to enforce things. But annoying users and blocking them to do local changes to their conanfiles was really a support burden.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The non-strict behavior seems fine for development and testing, but if this is the default behavior I'm sure someone from my team will commit changes to the conanfile that "worked for me" but won't push and updated lockfile.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, that makes sense. I understand now the reasoning why the non-strict mode was chosen as the default.
However, I think that in the above example with pkg/1.1
at least the lockfile needs to be updated automatically because without updating it we will end up with lockfile pointing to pkg/0.1
, while the actual resolved package will be pkg/1.1
. In this particular case, the conanfile and lockfile are incompatible (conanfile requires range [>=1.0 <2.0]
, and lockfile points to version 0.1
) - this needs to be resolved somehow - either by warning the developer about the compatibility (maybe it does not need to be a hard error, like in strict mode) or by updating the lockfile so that the change would be visible in the lockfile diff when committing. It feels weird that conanfile takes precedence over locfile in cases like this.
I agree that CI could always use the strict mode, but it would be even better if the developer could be informed about the incompatibility between the changed conanfile and the existing lockfile as soon as possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To ensure I understand correctly, if instead the conanfile
was updated to:
[requires]
pkg/[>=0.0 <2.0]
Would your example command work and build with pkg/0.1
as described in the lockfile even if pkg/1.1
existed?
conan install . --lockfile=conan.lock # will work
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, exactly. It will still lock to pkg/0.1
.
design/034-new_lockfiles.md
Outdated
If we do: | ||
|
||
```bash | ||
conan install . --lockfile=conan.lock --lockfile-strict # will not work |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I argue that the strict
mode should be the default and give non-strict
option to developers. See my previous comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it makes sense to allow the default to be set in conan.conf
, so this can be propagated using existing using conan configuration synchronization mechanisms and have a sane default for different use cases?
For a group actively developing a large set of conan packages and using a complex CI mechanism with a lot of package changes being made by experts in Conan, non-strict is a great default.
On the other hand, if a group is primarily developing a large complex application that uses conan packages but most developers are not conan experts, strict is a better default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the criteria is the size of the application. Our rationale is more on the line of UX:
- By default don't annoy developers being strict, or forcing them to add
--lockfile-no-strict
, or to configure something different with aconf
that will not match what is done in the servers (recall that conf can be synced and installed withconan config install
, in theory to match what the CI is doing). Let them do the changes that they want. In any case they don't have publish permissions to the servers, only CI should be able to upload packages. They won't break anything for not being stricts. - The CI is scripted. They know well which operations they want to be strict and what other can be not-strict, depending on their flow and process definition. As it seems the majority of lockfile operations would require non-strict for the most common flows (see above New 2.0 lockfiles #34 (comment)), we have favored the non-strict.
conan lock create . --lockfile-out=conan.lock -s os=Windows -s:b os=Windows | ||
# That captures a lockfile with ``win/0.1`` | ||
conan lock create . --lockfile=conan.lock --lockfile-out=conan.lock -s os=Linux -s:b os=Linux | ||
# That will augment the conan lock and it will end with both ``win/0.1`` and ``nix/0.1`` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be great if it were possible to do both that in a single conan invocation, at least with profiles.
Something like:
conan lock create . --lockfile-out=conan.lock --profile windows-profile --profile linux-profile --profile ios-profile --profile android-arm64-profile --profile emscripten --profile macos-profile ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be easily implementable with the custom commands and the public API at your will.
Note that your example, for a start is already having a different behavior, as multiple --profile
arguments in CLI actually compound and collapse into a single one. So a new syntax would be necessary to define such different profiles. Multiply that by 2 (host and build profiles), and by 3 for (settings, options, conf, that are also part of the profiles), and we have made the conan lock create
CLI arguments a nightmare, that would probably not satisfy many users.
But with the custom commands you can perfectly define what you want, what arguments you will be providing, the behavior that you want, and using the Conan Public API, you will be able to code it in relatively few lines (and distribute your custom commands with conan config install
too)
self.requires("dep/0.2") | ||
``` | ||
|
||
When the above steps for both Windows and Linux are executed, the resulting lockfile will contain both ``dep/0.1`` and ``dep/0.2``, including the latest revision for each one, but subsequent ``conan install --lockfile`` installations will still be able to resolve to the correct one, down to the locked recipe revision. This is based on the fact that the locked version still needs to match the required one, so when in Windows, it will look in the lockfile for ``dep/0.1``, will find it there, and will obtain the locked recipe revision from the lockfile. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, essentially, this looks like all different conan v1.X lockfiles are now merged together into a single giant lockfile?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, the Conan 1.X lockfiles were basically unmergeable, because they contained a graph, with numbered nodes for each package.
Conan 2.0 lockfiles are just lists of package references, merging them yes, is basically merging the lists and re-sorting them, in a largest lockfile.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I get it. This is why I stated above that it looks like a regular conanfile that does not use the version ranges. Of course, it also captures recipe revisions which we still don't use as we find it easier to reason about making a new minor/bugfix version when fixing the recipe - it's more transparent and removes the need for lockfiles which we also didn't need to use.
Yes, this does mean that we have packages like OpenCV/4.5.5.4@company/stable
instead of having 4 revisions of OpenCV/4.5.5@company/stable
, but it's more transparent and easier to reason about than having recipe revision hash in the conanfile or by using lockfiles.
Of course, since Conan v2.0 lockfiles are so much simpler, it may now have a sense for us to switch to using recipe revisions, but we'll see about that.
All in all, you did great work with the new lockfiles proposal!
Not sure i already understand all implications of this approach but here are some first questions:
class Pkg(ConanFile):
settings = "os"
def requirements(self):
if self.settings.os == "Windows":
self.requires("dep/[>0.0]")
else:
self.requires("dep/[>0.1]") Let's assume the first |
Yes, if you recall one of the previous Tribe proposal, the dependency graph will always be complete, containing all requires, and tool_requires. It will be able to skip fetching the heavy binaries, but at least the recipes that model what dependencies are involved will always be fetched and be part of the graph. That means that lockfiles will always be locking the full set of dependencies, and transitive dependencies, including
No, the |
Hi @a4z
At least there is a well known, documented and supported way to sync profiles across developers and CI machines, which has proven to work reliable.
One of the previous Tribe proposals agreed on the package immutability, which means that the revisions guarantee that the origin of the package is irrelevant. As lockfiles lock revisions, they will be able to resolve the package succesfully and correctly between multiple remotes. Furthermore, the fact that lockfiles doesn't lock the remotes is a desired feature, given that package promotion between remotes is a known good practice and is already being followed by users. You can get a lockfile against ConanCenter, then use it to install later and store a copy in your own private server, then disconnect from ConanCenter (something many users do), and the lockfile will still be working correctly. |
There are real world scenarios where getting a package from a remote like CCI is totally unwanted, or even prohibited. and I do not know what you mean that it's a problem to distribute a lockfile, the lockfile is saved in git alongside to a project, and can exactly restore todays, or yesterdays state. You do not want to have that all the sudden, yesterdays state is created with a library from a different remote. The profile information in the lockfile was absolute handy to have, especially in scenarios where global profiles are used (to share profile state/info) . Or how else would you get the options set saved over time in git ? How shall a lockfile allone restore/resolve the package successfully if it does only have the recipe revisions, but not the info about env and option from a profile. |
We have thought about it, but we went finally with the "explicit is better than implicit". The thing is that having a "conan.lock" file there, that can easily be generated by some commands, and be automatically used, generates the opposite "I want to be able to install, but don't pick the default lockfile", so that would require a But the question is very valid, lets thing about this, see what other people think, I will also discuss with the team.
The idea is that the process of capturing a lockfile for different configurations result in a final valid lockfile for all of them, but not necessarily exactly the same along the process. Does this make sense? |
- Lockfiles files will be json files containing only three lists of ordered references. One list for “host” requires, another list for “build” requires, another list for “python” requires. | ||
- Lockfiles will no longer contain information about profiles, settings, options (as they did in 1.X) | ||
- Lockfiles will not contain information about the dependency graph, only ordered lists (ordered by version and revision timestamp) of package references. | ||
- The default level of locking will be locking down to the recipe reference, that is, including the version and the recipe revision (``pkg/version@user/channel#recipe_revision``), but not the package-id nor the package-revision. This is aligned with the previously accepted Tribe proposal of removing the [``package_revision_mode``](https://github.com/conan-io/tribe/pull/30). Even if implementing lockfiles locking down the package revision will be possible, that will be considered the exception, and the main flows, documentation and behavior will be optimized for locking down to the recipe revision. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think leaving the package_id out of the lockfiles opens the doors for unwanted behaviors.
We use the lockfiles to achieve reproducible builds, particularly, to "ignore" new packages pushed to our repo unless we explicitly ask for them by updating our lockfiles.
Consider lib_a
, which has a neon
option set to False
by default. If someone builds this package with neon=True
and pushes it to our repo then our builds will start using a completely different package. Currently the lockfiles prevent this since the package_id is of each package is taken into account.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually the current 1.X implementation doesn't substitute the package_id
, it is also computed, and then validated.
There is a mode in the proof of concept that locks down to the package_revision
, that includes the package_id
. In the proof of concept it is only used to lock the package_revision
, which is the real moving part, but I guess that validation of the package_id might be possible too, it seems adding "strict" check there is doable.
Consider lib_a, which has a neon option set to False by default. If someone builds this package with neon=True and pushes it to our repo then our builds will start using a completely different package. Currently the lockfiles prevent this since the package_id is of each package is taken into account.
In your case, someone creating a package with neon=True
and pushing it to the repo, will not make it being used by consumers, unless consumers and profiles explicitly change to neon=True
too. I think for the vast majority of cases this won't be an issue in practice. In the very extreme case, it would be possible to store a copy of the original profiles together with the lockfile, to be robust against possible future changes in the profiles.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I work with @ericriff FYI)
I think forcing the whole set of packages used to be locked to recipe_revision
level addresses this.
We have had issues in the past where someone updates a package recipe (but not the version) and then builds that with a different option, which breaks building of older versions of our application. In our top-level application conanfile.py
we specify all packages down to recipe_revision
, but inter-package dependencies do not have a recipe_revision
.
For example:
app/1.0
-> pkga/0.1@user/channel#RREV1
-> pkgb/0.1@user/channel
. In this case app/1.0
specifies the full rrev of pkga
, and pulls in pkgb
implicitly with its default options (IE neon=False
). Another app developer wants to use pkgb
with neon enabled, but also fixes a minor issue in the recipe of pkgb
when doing so. That developer also updates pkga
to use pkgb
with the neon=True
option, and generates at least a new rrev if not also a new version (either way does not change this example). When we build our packages, we build the most recent version of all recipes and upload the binaries to our artifactory conan server.
We now have binary packages pkgb/0.1@user/channel#RREV1
with neon=False
and pkgb/0.1@user/channel/RREV2
with neon=True
.
The developer updates the conanfile for app/1.1
to build with pkga/0.1@user/channel#RREV2
, and builds of that are happy. However, now builds of app/1.0
fail: when resolving pkgb
it resolves to the most recent rrev of pkgb/0.1@user/channel#RREV2
, but there is no binary of that package with neon=FALSE
which is what pkga/0.1@user/channel/RREV1
requires.
We have many developers working on parallel on app
from branches of various ages including release branches a few months ago, developer branches made a week or two ago, and bleeding-edge builds. Suddenly having a large portion of our developer community unable to build older code because we updated a second-order dependent conan package caused us a few big headaches, and turning on lockfiles for the app fixed that issue.
I think this current plan of simply locking all direct and indirect references down to recipe_revision
is sufficient to address this issue for us, but I wanted to describe it in detail so we could all consider it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that is my understanding. Lockfiles capture the direct and transitive dependencies, so it doesn't matter if some other teams create a new recipe revision that only builds with a certain option, because that will not impact at all, that new revision will not be resolved by the first developer/team.
A different discussion of course is whether building only a subset of binaries, for example, only neon=True for RREV2, and not neon=False, knowing that it will disrupt developers that might upgrade to get the latest RREV2 recipe improvements. In principle, I would tend to favor the creating of binaries when source changes. If recipe gets a new RREV2, that should be built and green for the different configurations, or otherwise rejected. Because the thing is that it is not only that there is no pre-compiled binary for neon=False
, but that change might completely break that option, and when downstream consumers don't find the binary and do --build=missing
that build will fail without solution, that is problematic.
But I know it is a balance or trade-off between different things, so in any case, I think it will be good with the lockfiles always locking the full dependency graph down to the recipe revision.
design/034-new_lockfiles.md
Outdated
- Lockfiles will no longer contain information about profiles, settings, options (as they did in 1.X) | ||
- Lockfiles will not contain information about the dependency graph, only ordered lists (ordered by version and revision timestamp) of package references. | ||
- The default level of locking will be locking down to the recipe reference, that is, including the version and the recipe revision (``pkg/version@user/channel#recipe_revision``), but not the package-id nor the package-revision. This is aligned with the previously accepted Tribe proposal of removing the [``package_revision_mode``](https://github.com/conan-io/tribe/pull/30). Even if implementing lockfiles locking down the package revision will be possible, that will be considered the exception, and the main flows, documentation and behavior will be optimized for locking down to the recipe revision. | ||
- Locking by default will be non-strict, that is, if some ``requires`` cannot find a matching locked version in the lockfile, it will be resolved normally. A ``--lockfile-strict`` mode will be implemented, but not the default, to enforce finding a match for declared requires in the lockfile or failing otherwise. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My intuition tells me that lockfiles should be honored 100% of the times to ensure reproducible builds.
- The default level of locking will be locking down to the recipe reference, that is, including the version and the recipe revision (``pkg/version@user/channel#recipe_revision``), but not the package-id nor the package-revision. This is aligned with the previously accepted Tribe proposal of removing the [``package_revision_mode``](https://github.com/conan-io/tribe/pull/30). Even if implementing lockfiles locking down the package revision will be possible, that will be considered the exception, and the main flows, documentation and behavior will be optimized for locking down to the recipe revision. | ||
- Locking by default will be non-strict, that is, if some ``requires`` cannot find a matching locked version in the lockfile, it will be resolved normally. A ``--lockfile-strict`` mode will be implemented, but not the default, to enforce finding a match for declared requires in the lockfile or failing otherwise. | ||
- A single lockfile file can lock multiple configurations, for different OS, compilers, build-types, etc., as long as they belong to the same graph. Lockfiles can be constructed for these multiple configurations incrementally, or they can be merged later. The concept of “lockfile bundles” will no longer be necessary | ||
- Lockfiles will not be a version definition mechanism, they need to be a “realizable” snapshot of a dependency graph that should be able to be evaluated in the first place. However, they will allow their usage to define overrides or definitions of versions or recipe revisions that will be used if they fit in the valid definition of the original ``requires`` (that is, if the version fits in the version range of the recipe ``requires``, or always for recipe revisions) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you be a bit more explicit on what a version definition mechanism
means?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that means, that you cannot have a conanfile.txt
containing a [requires] dep/0.1
, then capture a lockfile for it, then edit the lockfile to contain dep/0.2
, apply it to conanfile.txt
and expect that it will resolve to dep/0.2
.
Lockfiles cannot be use to define a dependency, they can only be used to lock the moving or missing pieces of a requires
to a fixed value. In most cases that means a lockfile can pin an exact version of a dependency in a given version range, and a lockfile can pin a recipe revision. But the definition of the dependency in conanfile
requires
should always be respected.
- Locking by default will be non-strict, that is, if some ``requires`` cannot find a matching locked version in the lockfile, it will be resolved normally. A ``--lockfile-strict`` mode will be implemented, but not the default, to enforce finding a match for declared requires in the lockfile or failing otherwise. | ||
- A single lockfile file can lock multiple configurations, for different OS, compilers, build-types, etc., as long as they belong to the same graph. Lockfiles can be constructed for these multiple configurations incrementally, or they can be merged later. The concept of “lockfile bundles” will no longer be necessary | ||
- Lockfiles will not be a version definition mechanism, they need to be a “realizable” snapshot of a dependency graph that should be able to be evaluated in the first place. However, they will allow their usage to define overrides or definitions of versions or recipe revisions that will be used if they fit in the valid definition of the original ``requires`` (that is, if the version fits in the version range of the recipe ``requires``, or always for recipe revisions) | ||
- Lockfiles will be allowed to evolve and adding new information to them easily, at ``conan install``, ``create``, ``graph``, and ``export`` operations, specifying a ``--lockfile-out=newlockfile`` argument. That will allow evolving lockfiles when changes are done to the graph, while keeping control on those changes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this. Currently we delete and recreate the lockfiles each time we need to change 1 (or more dependencies). I'd like them to be able to change organically. poetry
(python package tool) does a great job with this.
We maintain a huge, ever growing C++ project which uses conan only to consume its third party dependencies. We have lockfiles to ensure the builds are 100% reproducible, now in the past and in the future. What I mean is, we expect to be able to checkout a 6 months old commit, and as a consequence have a 6 months old lockfile and then be able to build that commit using the exact snapshop of dependencies we used at that point in time.
The problem we currently have is that when we're developing a new feature and add a new dependency or modify an existing one on our conanfile
then we need to nuke our lockfiles and create new ones. As a consequence we update many packages from the lockfiles and not only the one we want (usually our conan remote moves faster than out codebase). I'd like to see a command that allow us to partially update a lockfile, like add a new dependency or change some version without affecting the rest (as much as possible).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is one of the biggest pain points at the moment in 1.X. And a lot of this proposal is intended to reduce or eliminate it.
The basic conan lock create
command, can receive a --lockfile=xxxx
argument, to use it as a starting point, then produce the output with --lockfile-out
. That includes a lockfile from a previous point in time, from a subgraph, or from a different configuration. The resulting output lockfile will be the updated previous one, the things that can be locked from the previous one will be respected, the things that have changed or are new, will be added to the lockfile. To remove legacy, no longer used dependencies in the lockfile, the --clean
argument can be provided too.
design/034-new_lockfiles.md
Outdated
conan install . --lockfile=conan.lock # will work | ||
``` | ||
|
||
Will not fail by default, and will be able to resolve to ``pkg1.1``. This is because the default mode is non-strict. One of the most frustrating behaviors of Conan 1.X lockfiles was when lockfiles didn’t allow you to do modifications to your conanfiles and keep working. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The non-strict behavior seems fine for development and testing, but if this is the default behavior I'm sure someone from my team will commit changes to the conanfile that "worked for me" but won't push and updated lockfile.
But this can be easily controllable with
If you put the lockfiles inside a repo, and the
The configuration of settings and options (and other stuff) will still come from profiles. The need to maintain, share and use profiles doesn't dissapear, because they are necessary in the first place. So instead of having multiple profiles named This proposal is about decoupling responsibilities:
|
I mentioned, that does not scale and people manage to have wrong configs, in restricted environment, with a CCI as default, a real problem.
This is not the problem I have, nor I ever had. The only remote config should be the internal artifactory. urls within there may vary, but having this over time going with the code, e.g. switch from testing to stable packages, is wanted
This theoretical scenario never effected my workflows, usually I know exactly what I want. No version ranges, no alternatives, always strict, in fact, I would love to see package revisions kept, but I understand that this is a problem.
libcurl uses openssl on linux, and no openssl on Mac, how shall they have the same lockfile when they use different packages?
I agree that everything should come from profiles, but what is with command line arguments that add setting to conan (lock) create ? And I usually need them in one place. That was awesome in the current lockfiles, except, only I missed the remote. |
I understand this is a concern, but please see comments in #34 (comment). If developers need to add |
Great rework here, it sounds like a better approach in terms of developer experience 👏 With this new locking system, could conan somehow generate the lock file automatically upon With such a feature, the developer would not need to mind about lock files most of the time (i.e. handling Some people might not want to have this behavior by default. It could be behind an option in For those who are not familiar with npm: Difference between npm i and npm ci |
Hi @vdsbenoit
Yes, this might be possible, as those commands already have the Under a multiple configuration scenario, it is better to first lock all possible configurations, as fast as possible, and ideally in just 1 machine, no need to distribute the command to different machines to capture this lockfile. This is possible with a But I agree that specially for the developer experience, it might make sense to enable the lockfile output directly from |
Co-authored-by: Peter Bauer <peter.m.bauer@gmail.com>
I have poetry and pipenv in mind here as examples. The respective
thx!
I understand but the lockfile then does not fully cover the "freeze the dependencies as they are" use-case. To be 100% sure one would need to maintain separate lockfiles for such an "exotic" dependency tree. |
I think that "restricted environment" and "CCI as default" shouldn't be together in the same sentence 😃 . As @memsharded already mentioned, in restricted company environments you should distribute your custom config to all your developers that has CCI removed. We do that and our developers cannot accidentally fetch any package from CCI. If they need a package from CCI, it first gets imported into our private Artifactory, possibly after recipe modification (this is necessary as most recipes in CCI are not able to build a mac/ios universal binary that we usually put in our packages).
Well, this is also what we do - no version ranges, no package revisions, and, therefore, no need for lockfiles - in either old or new form. Why do you then feel you will get affected by this change? My company most surely won't be, but nevertheless, I still think this is a good change.
The exact same example has been described in the proposal and what will happen.
As far as I understand, those will now be encoded within the single lockfile. So instead of having separate lockfile for each profile, you will have "all those lockfiles" merged in a single lockfile. Also, please see this conversation. |
DoDoENT That you are in a now perfect environment is nice for you. The difference about
and
is of course ... Maybe when I see that in action, my mind will adopt and change, that is usually what happens. I usually have huge trust in the conan team that they do the right change. |
@a4z , I see what you mean and I understand. However, when comparing
and
It's much more consistent than using Yes, it's a super breaking for cases like yours. But it will make general experience more consistent. And Conan v2.0 is the breaking release anyway (new cache format, new toolchains and generators, mandatory lower-case package names (which I still don't like 😛 ), ...) so IMO it's better to make that change now than be sorry later. |
Yes, of course, if for some reason you really want to have the Windows build use
Sometimes, when the apps are relatively coupled, like they are part of some larger systems, the first behavior might be preferred, while if the apps are completely unrelated products, the second is the way to go. In general, one of the things that I like most about the new lockfiles is their conceptual simplicity: "an ordered list of package references", that will be used while resolving a graph. There is nothing intrinsic to them that force you to use them for just one configuration, one product, one version... You can perfectly feed one lockfile from one product/app into a different product/app, or you can feed it from one version to the next version, or from one configuration to a different configuration. Or you can keep them separated if that is what you want for your use case. Note, however, that for the case described above and your ""freeze the dependencies as they are", I still think that having a single lockfile resolving to |
|
||
The largest implementation effort had to be done on the preconditions to have this lockfile model, basically: | ||
|
||
- To have ordered lists of versions and revisions, it was necessary to attach the revision timestamp to every recipe reference in the whole model. That was a massive change, affecting a very large part of the codebase, and took a while to stabilize. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a new syntax to specifying recipe revisions? Can you describe how this was changed or provide a pointer to that document?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new syntax will probably be only used and visible in lockfiles, where something like pkg/version#recipe_revision%timestamp
will be there, to allow the ordering of revisions.
Internally we had to change all the model of references in order to propagate together the timestamp with the revision, just for the lockfiles, but for normal operation of Conan nothing changes. The pkg/version#recipe_revision
is still a full, deterministic coordinate of that recipe, it can be used as an input to commands, etc.
This is a great observation, because actually there is a case, the one that does conan lock add
specifying a reference including the recipe revision, when other references for exactly the same version with their recipe revision already exist. In that case, it might be necessary to specify the timestamp if we want to define the correct ordering. I am creating a follow up issue for this, because this needs to add some testing, and there could be some UX to polish around this use case.
Update: new issue conan-io/conan#11129
In general the proposal looks good, better alignment and interplay between recipe and lockfile in particular. I'll point out that many of our teams have a relatively small set of devs who are responsible for and familiar with the conan config and updates. For other devs we want to provide as few and concise of commands as possible to facilitate updating. They don't need awareness of conan nuances, especially having to remember to add extra flags to executions which are usually the default desired behavior. We and they just want the easiest path to obtain a known and deterministic state. It's not simply a discussion of boolean distinction between "local dev" vs "CI execution". With that context in mind, I'll emphasize that it's important to consider the conan-consuming developers' UX experience at least as much as the conan-changing developers', in particular that the frequency of execution of commands to update recipe and lock files may be much less frequently used than commands to install or updated based on an existing lockfile. Further I'll echo and agree with concerns raised and discussed elsewhere, that I'd like to see.
|
I already tried when doing PR conan-io/conan#11135, and I found these cases:
So it seems that |
I'll also offer my request and two cents towards considering having the lockfile default be alongside the recipe instead of cwd. By far the most common use case we encounter is recipe and lockfile tracked in source control, and an out of source build tree, with steps similar to the following. Some of these steps are often wrapped in a helper script run by devs instead of running the conan command directly.
As for the examples you offer, both seem more like corner cases where using |
Fair enough, I think there are pros and cons, but your proposal also makes sense. So unless someone else thinks contrary, I am proposing these changes:
I will also try them first in code in the PR, then when that PR is merged, I will come back to change this proposal. |
That makes more sense to me when lockfiles don't contain profile information and can work with multiple configurations, in contrast to v1 lockfiles (when it's per-configuration then it's better to keep it in build folder). Also, I got impression that it's safe to update |
yes, it is safe to update |
Some of the previous comments seem to evolve around the following questions: What are lockfiles used for?We use lockfiles to make dependency resolution deterministic e.g. reproducible. What it sometimes used for?Some of the comments suggest (and actually this is also how I inteded to use them) is to preserve state.
Where on the second / third invokation all variables from the first invokation are still in place. I think that Conan would also benefit from having a cache, to make subsequent invokations easier. |
Hi Tribe! The PR conan-io/conan#11135 with the necessary changes from your feedback to the proof of concept has been merged (it will be part of alpha.7), and this proposal has already been updated to incorporate this feedback too, check the latest commit: 2b9b968. As the capturing of combined profiles is mostly a UX improvement/requirement, but doesn't imply any functional logic to how the lockfiles work in 2.0, it doesn't need to get a solution right now in this proposal, and a new issue in conan-io/conan#11155 has been created for it, we will be working there to provide the best possible UX when the first hands-on feedback starts coming. |
Just trying to wrap my head around this...in the middle of trying to make things work with 1.X lockfiles...so I have some context. It sounds a bit like Conan 2.0 lock files will have some resemblance to Conan 1.0 lockfiles with the |
Yes, exactly. This is what we learned from Conan 1.X, we had to implement the But you are right, they don't allow being used directly, they were designed as a base for the full lockfiles, but not for direct usage. It would be possible to implement, but it was not easy. So yes, this proposal for 2.0 not only allows to specify profile, the new lockfiles need a profile to be specified, because they will only capture version and revision information, but not configuration. They idea is that commands always look the same, using or not using profiles: conan create . -pr:h=linux -pr:b=windows
conan create . -pr:h=linux -pr:b=windows --lockfile=mylockfile
conan create . -pr:h=rpi -pr:b=windows
conan create . -pr:h=rpi -pr:b=windows --lockfile=mylockfile
conan install. -pr:h=linux -pr:b=windows
conan install. -pr:h=linux -pr:b=windows --lockfile=mylockfile
.... |
It would be good to see more practical examples...some of it seems a bit abstract.
|
Yes, the idea of these proposals are that they are mostly conceptual, architectural and strategic, deprecations, evolutions... What you are asking is basically:
This will work well for consuming. For creating packages it should be noted that commiting new files to the repo can change the recipe revision (when using Evolving the lockfiles is possible, for example: conan lock add --requires=mydep/1.1 Assuming the lockfile had previously |
I understand...but practical examples also make for clearer discussion of the issues and potential problems/gaps.
Well perhaps |
Yes, as I was saying, a Because it is possible that for many cases, it is not even necessary. For example, when processing the changes that actually bump |
One completely different though which has just popped up (which I didn't explicitly see before), is how this proposal relates to version controlling lockfiles. E.g, at the moment we do have the following workflow:
With 1.x lockfiles can become quite hard to compare. Are lockfiles meant to be version controlled? Are they meant to mergeable? |
yes. This is how a lockfile looks like: {
"version": "0.5",
"requires": [
"pkgc/0.1#4d2acb63aa360295c54a1811799a5e87%1652111238.2041075",
"pkgb/0.2#476b31358d78b3f04c68c4770bd6a79c%1652111239.1558757",
"pkgb/0.1#43511a4669edc78292516e6cbf00c0b2%1652111238.0599482",
"pkgawin/0.1#2f297d19d9ee4827caf97071de449a54%1652111237.7507892",
"pkganix/0.1#2f297d19d9ee4827caf97071de449a54%1652111237.9206934",
"app1/0.1#34d26743473acd7f8d8026502501c170%1652111238.346824"
],
"build_requires": [],
"python_requires": []
} As they are ordered lists, one element per line, and always sorted, it is expected that they would be relatively easy to merge and version control.
Yes, because merging ordered lists is something that is possible. We implemented a convenience
The result of the merge doesn't guarantee a fully "clean" lockfile (it can contain not used dependencies versions/revisions) because it doesn't evaluate the dependency graph, but the merged lockfile can be perfectly used to resolve and lock dependencies, and can be |
Are they ordered or are they sorted? Sorted lists are indeed easy to merge, but for ordered it is impossible (at least in general case): For example, if 2 packages are in reverse order (e.g. one lockfile "downgraded")? This somewhat reminds about conflict resolution in SCM (as source code is an ordered list of lines :D ) which quite often is wrong. |
@ytimenkov I didn't know there is a difference between |
Yeah... Got me 😕 What I apparently was thinking about is that "sorted" is according to internal properties, like lexicographical name or semver version. While "ordered" is according to external order, like "in order of insertion". Dictionary says "sorted" is also grouped or "in certain order". While "ordered" means (to me) that you can't reshuffle things, more general.🤷♂️ |
Small remark regarding that, it would be nice if this made it to the final version and it could take an arbitrary number of lockfiles to merge into one (i.e. nargs="*" for the input lockfiles). |
The lists are sorted by version and revision timestamp, to account for the logical resolution within ranges, and revisions. Should be good for source control.
Yes, it is multiple input :) def lock_merge(conan_api, parser, subparser, *args):
subparser.add_argument('--lockfile', action="append" |
Conan 2.0 will implement completely new lockfiles, with a new proposal of format, definition, behavior, usage and flow, based on the following principles:
pkg/version@user/channel#recipe_revision
), but not the package-id nor the package-revision. This is aligned with the previously accepted Tribe proposal of removing thepackage_revision_mode
. Even if implementing lockfiles locking down the package revision will be possible, that will be considered the exception, and the main flows, documentation and behavior will be optimized for locking down to the recipe revision.requires
cannot find a matching locked version in the lockfile, it will be resolved normally. A--lockfile-strict
mode will be implemented, but not the default, to enforce finding a match for declared requires in the lockfile or failing otherwise.requires
(that is, if the version fits in the version range of the reciperequires
, or always for recipe revisions)conan install
,create
,graph
, andexport
operations, specifying a--lockfile-out=newlockfile
argument. That will allow evolving lockfiles when changes are done to the graph, while keeping control on those changes.NOTES: