-
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
Changes from 4 commits
9fdbb70
a851c42
62f55c2
f029783
2b9b968
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,237 @@ | ||
# Proposal: New Conan 2.0 lockfiles | ||
|
||
| **Status** | | | ||
|:------------------|:--------------------------------------------------| | ||
| **RFC #** | [034](https://github.com/conan-io/tribe/pull/34) | | ||
| **Submitted** | 2022-04-26 | | ||
| **Tribe votes** | | | ||
|
||
|
||
## Summary | ||
|
||
Conan 2.0 will implement completely new lockfiles, with a new proposal of format, definition, behavior, usage and flow, based on the following principles: | ||
|
||
- 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 commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually the current 1.X implementation doesn't substitute the
In your case, someone creating a package with There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 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 For example:
We now have binary packages The developer updates the conanfile for We have many developers working on parallel on I think this current plan of simply locking all direct and indirect references down to There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 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. |
||
- 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 commentThe 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 commentThe 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:
One of the first implementation we had was the other way around, strict by default. When we realized that we were basically either saying 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 commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. If I understand correctly:
Is this a correct interpretation @memsharded ? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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:
Specifying |
||
- 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 lockfiles will still not contain information about settings, options or profiles for those different configurations, but they will be able to contain different locked ``requires`` for the different configurations. 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 commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. No, it will at least also include the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you be a bit more explicit on what There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that means, that you cannot have a Lockfiles cannot be use to define a dependency, they can only be used to lock the moving or missing pieces of a |
||
- 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 commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
|
||
## Motivation | ||
|
||
Lockfiles in Conan 1.X were born mainly driven by the need of doing distributed builds in CI, and ensuring the same dependencies were used in this build. They achieved this goal, but not without some pain derived from the fact that the dependency resolution algorithm in Conan 1.X is non-deterministic related to the cache state, that means that 2 different packages with the same dependency and the same version range could resolve to different versions, if some other package in between were forcing the download of a new version in that range from a server. | ||
|
||
That resulted in the need to store the full dependency graph in the lockfiles, and as the dependency graph is so tightly coupled to configurations, it required to store one lockfile per configuration, which also added the profiles information, as a "convenience", trying to simplify the management a bit. But locking the full dependency graph made things very challenging, because the algorithm needs to fully identify a match for a package inside that graph, before being able to resolve the locked dependencies. And basically making it almost impossible to do “merge” operations over different lockfiles, and to use a partial lockfile from one graph to resolve other dependencies. It also made necessary to have a very strong locking, because losing the consistency of the dependency graph between locked and unlocked parts was unmanageable. | ||
|
||
All of that resulted in lockfiles that have been able to partially address some of the related problems, but that in general are complex to use, understand, and implement CI with them. | ||
|
||
So, for Conan 2.0, we are proposing a way more “traditional” approach to lockfiles, with the simplifications enumerated above, making Conan lockfiles something closer to what other package managers like NPM can do. There were a few unknowns if this was doable, so for this proposal we wanted to implement it first, check below for details. | ||
|
||
## Detailed Design | ||
|
||
In the surface, the basic usage of lockfiles hasn’t change much, creating and using a lockfile would be: | ||
|
||
Lets say we have conanfile.txt: | ||
|
||
``` | ||
[requires] | ||
pkg/[>=0.0 <1.0] | ||
``` | ||
|
||
And existing ``pkg/0.1`` then: | ||
|
||
```bash | ||
conan lock create . --lockfile-out=conan.lock | ||
# this will create a lockfile with a “requires” list containing “pkg/0.1” | ||
# no matter if other new version pkg/0.2 in the range is created now | ||
# this will keep resolving to “pkg/0.1” | ||
conan install . --lockfile=conan.lock | ||
``` | ||
|
||
But many things have changed, lets see them. | ||
|
||
### Non-strict vs strict | ||
|
||
If we now do a modification to our conanfile.txt to: | ||
|
||
``` | ||
[requires] | ||
pkg/[>=1.0 <2.0] | ||
``` | ||
|
||
And assuming a ``pkg/1.1`` version exist, then: | ||
|
||
```bash | ||
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 commentThe 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. 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe 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 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 commentThe reason will be displayed to describe this comment to others. Learn more. To ensure I understand correctly, if instead the
Would your example command work and build with conan install . --lockfile=conan.lock # will work There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, exactly. It will still lock to |
||
|
||
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 commentThe reason will be displayed to describe this comment to others. Learn more. I argue that the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe it makes sense to allow the default to be set in 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 commentThe 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:
|
||
``` | ||
|
||
It will throw an error saying that the requirement ``pkg/[>=1.0 <2.0]`` cannot be found in the lockfile | ||
|
||
### Multi-configuration lockfiles | ||
|
||
If we have one conanfile like this: | ||
|
||
```python | ||
class Pkg(ConanFile): | ||
settings = "os" | ||
def requirements(self): | ||
if self.settings.os == "Windows": | ||
self.requires("win/[>0.0]") | ||
else: | ||
self.requires("nix/[>0.0]") | ||
``` | ||
Then it will be possible to capture the lockfile for both Windows and Linux configuration in a single lockfile file, in the following way, assuming there exist packages ``win/0.1`` and ``nix/0.1``: | ||
|
||
```bash | ||
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 commentThe 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:
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 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 |
||
``` | ||
|
||
The later application of the same single resulting “conan.lock” lockfile works for both Windows and Linux configurations: | ||
|
||
```bash | ||
conan install . --lockfile=conan.lock -s os=Windows -s:b os=Windows | ||
# resolves to win/0.1, but of course nix/0.1 will not be part of the resulting graph | ||
|
||
conan install . --lockfile=conan.lock -s os=Linux -s:b os=Linux | ||
# resolves to nix/0.1, but of course win/0.1 will not be part of the resulting graph | ||
``` | ||
|
||
This approach remains valid when different configurations resolve to different versions of the same package. If the package ``conanfile.py`` is: | ||
|
||
```python | ||
class Pkg(ConanFile): | ||
settings = "os" | ||
def requirements(self): | ||
if self.settings.os == "Windows": | ||
self.requires("dep/0.1") | ||
else: | ||
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 commentThe 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 commentThe 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 commentThe 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 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! |
||
|
||
|
||
### Partial lockfiles | ||
|
||
Let's say we have a dependency graph ``app``->``pkgc``->``pkgb``->``pkga``. | ||
|
||
We can capture a lockfile called “pkgb.lock”, while we are developing ``pkgb``, doing some changes to it, or building it in CI, that locks the dependencies of ``pkgb``, that is it will lock ``pkga/0.1`` Something like: | ||
|
||
```bash | ||
# in the pkgb/conanfile, assuming it ``requires = “pkga/[>0.0]”`` | ||
conan lock create . --lockfile-out=pkgb.lock | ||
# this pkgb.lock will contain a locked reference to say ``pkga/0.1`` | ||
# we can apply this lockfile locking only ``pkga`` all the way down: | ||
# moving to pkgc repo/folder | ||
conan install . --lockfile=pkgb.lock | ||
# this will lock only pkga/0.1, pkgb is not necessarily locked, we didn’t capture it | ||
# moving to app repo/folder | ||
conan install . --lockfile=pkgb.lock | ||
# this will lock only pkga/0.1, pkgb is not necessarily locked, we didn’t capture it | ||
``` | ||
|
||
In all the above cases, the lockfile contains ``pkga/0.1``, so when executing the different ``conan install --lockfile=pkgb.lock`` in differents ``pkgc`` or ``app`` repos, it will lock exclusively the ``pkga/0.1``, but not the other dependencies in the graph, as they were not added to the graph (it is possible to add them, it will be shown later, but they were not added in this example). | ||
|
||
With this in mind, it is then possible to define manually a lockfile with just one single package reference locked, and apply it later to resolve a full graph. Only the defined locked version will be used, while the rest of the graph will be evaluated as always, without locks. | ||
A ``conan lock add`` command will be provided, so it is more convenient to add things to lockfiles. | ||
|
||
Furthermore, it will also be possible to define partial references, that is, even if a lockfile by default captures the ``pkg/version@user/channel#recipe-revision`` full recipe reference, it is still possible to define with ``conan lock add`` a given ``version`` without specifying a recipe revision. In that case, when the lockfile is used, it will use the locked version, and it will resolve dynamically (to latest) the missing piece of recipe revision. | ||
|
||
|
||
### Modifying lockfiles | ||
|
||
Let's say we have a dependency graph ``pkgb``->``pkga``. | ||
|
||
We can capture first a lockfile for the dependencies of ``pkgb``, while we are developing it. It will contain only the locked version of ``pkga``. If we decide to ``conan create`` the ``pkgb`` using those locked dependencies, we can augment the existing lockfile to include the recently created ``pkgb`` version (and recipe revision) to the same or to a new lockfile: | ||
|
||
```bash | ||
# in the pkgb/conanfile, assuming it ``requires = “pkg/[>0.0]”`` | ||
conan lock create . --lockfile-out=pkgb.lock | ||
# this pkgb.lock will contain a locked reference to say ``pkga/0.1`` | ||
conan create . --lockfile=pkgb.lock --lockfile-out=pkgb.lock | ||
# now the pkgb.lock contains ALSO the locked pkgb version | ||
``` | ||
|
||
We have commented above that a ``conan lock add`` operation will be possible, to manually add a version. In the same spirit, it will also be possible to ``conan lock merge`` different lockfiles, as long as those lockfiles belong to the same dependency graph, partially or totally. But they should have shared some common root at some point in time. | ||
|
||
These modifications basically add new versions to an existing lockfile, but as such lockfile can be used for different configurations, it doesn’t remove non-used locked references automatically. In order to clean and strip unused references from a lockfile, an explicit ``conan lock create --clean`` creation of a lockfile will be possible. | ||
|
||
### Lockfiles in CI | ||
|
||
This proposal simplifies the lockfiles and removes some of the commands and functionality that Conan 1.X lockfiles implemented, and that is necessary for implementing CI flows. Conan 2.0 will enable these CI flows with the following functionality: | ||
|
||
- ``conan graph build-order`` will output the necessary build-order for a full dependency graph, returning an ordered list of lists, by concurrent-builds levels, in which things need to be built. | ||
- ``conan graph build-order`` will also return the necessary options that every given package in the build-order will need to apply (this information was previously hidden in the lockfile) | ||
- It will be possible to merge different build-orders, even from different products and different dependency graphs with ``conan graph build-order-merge`` which will result in a grouped view, for every package reference, in order, which binaries need to be built. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To merge 2 build orders 2 graphs are needed => 2 recipes. Lockfiles2.0 don't contain graph, do they? And build order is an operation on graph(s) which are no longer in lockfiles. Or do I miss something? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not necessarily 2 recipes, but maybe the same recipe with 2 configurations, you obtain 2 different dependency graphs, and they can result in different build orders, when conditional dependencies are defined for example. Yes, lockfiles no longer contains the graph definition, only lists of dependencies. The key is that the build-order is no longer an operation on the lockfile itself (as it was in 1.X), but on the graph. Exactly the same as the Please let me know if this clarifies it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My main concern was how will UI / CLI for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The output of
And then, multiple build-order files can be merged into a single one (typically resulting in more than one item in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, that makes sense. So in a way you moved graph from lockfile into build-order output. Since the latter needs to be processed by a tool, I don't see many problems with that. Except maybe that previous build-order output could be parsed by simpler regexp, while for that one a complete json parser is needed. So bash users could be unhappy 😁 (or they will have to use tools like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, exactly. The UI was weird in 1.X, in the sense that you really shouldn't need a lockfile in order to compute the build-order of a graph. So it was moved to the right location, Yes, you are very right regarding the full json output, but from what we have learned from users so far is that such json is being parsed by CI in the vast majority of cases (because the list-of-lists is not that simple to parse with regex either). And in 2.0 for those who want something simpler, it will be possible very easily, for example with a user custom command, you can process the build-order and output exactly in the format that you want to process it, with very few lines of code, and integrated and managed by Conan. |
||
|
||
The idea is that all commands work with the same syntax with and without lockfiles. For example the ``conan graph build-order`` commands above can also be used with and without passing a lockfile at all. | ||
|
||
The features designed above will enable 2 flows that were challenging, not to say almost impossible in Conan 1.X, in a straightforward way. | ||
|
||
Let’s say we have the ``app``->``pkgc``->``pkgb``->``pkga`` dependency graph, everything is at version ``0.1``, with version ranges like ``[>0.0 <1.0]`` and a developer does a change in ``pkgb`` and bumps its version to ``0.2``. | ||
|
||
Two flows become possible: | ||
|
||
1) Starting from ``pkgb`` with a partial lockfile: | ||
|
||
- Capture a lockfile for ``pkgb``, locking ``pkga/0.1``, so it can be used to test all different configurations for ``pkgb/0.2`` without risking a concurrent ``pkga/0.2`` is published during this operation. | ||
- Capture a lockfile for ``pkgb/0.2`` while creating ``pkgb/0.2``, including both ``pkgb/0.2`` and ``pkga/0.1``. | ||
- When ``pkgb`` builds correctly, if we want to test the downstream application, we can now capture a new lockfile for it, just feeding the ``pkgb`` one: | ||
|
||
```bash | ||
# in the app repository | ||
conan lock create . --lockfile=pkgb.lock --lockfile-out=app.lock | ||
``` | ||
|
||
- Now use ``app.lock`` to feed it to ``conan graph build-order`` or to ``conan install`` or to ``conan create --build=missing``. | ||
|
||
2) Starting from ``app`` full lockfile: | ||
|
||
- Capture the ``app`` product lockfile | ||
|
||
```bash | ||
# in the app repository | ||
conan lock create . --lockfile=app.lock | ||
``` | ||
|
||
- Apply the lockfile for the testing and creation of ``pkgb``, capturing the modified lockfile, to account for the new ``pkgb/0.2``: | ||
|
||
```bash | ||
# in the pkgb repository | ||
conan lock create . --lockfile=app.lock --lockfile-out=app.lock | ||
``` | ||
|
||
- Apply the ``app.lock`` that now includes the new ``pkgb/0.2`` downstream to rebuild ``pkgc`` and ``app`` as needed. | ||
|
||
Note that these flows do not require complicated structure or storage of multiple lockfiles. Just 1 single lockfile can be enough for the whole process. If the changes are to be tested for multiple, unrelated products (final consumers), then 1 lockfile for each one might be necessary, but still the complexity will be highly reduced. | ||
|
||
|
||
## Implementation details | ||
|
||
As commented above, the unknowns were many and the uncertainty high, so we implemented this proposal, it is already available in the released alpha.6. It turns, that as the complexity of the lockfiles has been reduced so much, the implementation was also way more straightforward, like one order of magnitude, compared with Conan 1.X lockfiles. | ||
|
||
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 commentThe 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 commentThe 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 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 This is a great observation, because actually there is a case, the one that does Update: new issue conan-io/conan#11129 |
||
- It was necessary to implement a different graph resolution algorithm, in which the resolution was deterministic, in a way that it should be impossible to resolve to different versions within a range in the same dependency graph, as that would violate the working hypothesis. As the graph resolution algorithm had to be fully re-implemented to implement the Tribe proposal for requirement-traits and package-types, we took it into account. | ||
|
||
|
||
## Migration plan | ||
|
||
The new lockfiles share nothing with the Conan 1.X lockfiles. The files are different, the commands are different, and the flows that they enable are different. It will be necessary to implement new pipelines in CI for these new flows. The aim of this proposal is that these new CI pipelines for Conan 2.0 will be much simpler than those that already implemented then for 1.X. | ||
|
||
There is nothing in the recipes that affect lockfiles, so it will not be necessary to modify any ``conanfile`` to account for this proposal, only command line and lockfiles. |
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 know that profiles can be distributed with
conan config install
, but it is not always obvious which profiles or overrides were used in the build.E.g. now a CI job produces lockfile as an artifact which can be consumed later. Especially in "testing" or "deploy" jobs which call
conan lockfile install
. This information will be unavailable, right?Basically, what I'm looking for is a way to avoid discrepancy between which environment was used to build and to consume. Conan already have composable profiles and overrides via settings and options, and in our CI more overrides can come via environment variables or extra job parameters (e.g. if one wants an experimental build with specific settings).
I suspect is would be possible to implement this on top of Conan with custom CI scripts (e.g. create a profile file by aggregating data which otherwise would have been passed on the command line and pass only it as a single
--profile
argument and export as a CI job artifact), but maybe it's worth doing similar thing right in Conan. Like a "profile lock" which (if specified) would complement dependencies' lockfiles and have similar strict checks as with current lockfiles.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 am happy to see I am not the only one who is concerned about preserving profile information
(what I did and do so far via having them in the lockfile, and that correct and for free)
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 would also second the need to be able to capture/obtain the full settings/options context in order to be able to reconstruct the environment from binary package creation time.
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 actually realized one more use case for that: sometimes we use same profile name which is specific to particular docker image. Similar to preparing image with a compiler and then running
conan profile new default --detect
. Then we build using that image and 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.
I would say one of the most advantages of the lock files proposal is to have decoupled "locked versions/revisions" from the "configurations", managing a CI flow for building a project is way simpler and more consistent. Preserving the information from the applied lock file can be done separately, I'll open a new issue (2.X) to discuss the ways to do it, some alternatives could be (just to clarify what I mean):
With a different command:
conan profile compose --profile:h=foo -s:h arch=x86 -c myconf=1 --profile_out:h=profile_host_windows_x86.txt
Directly with arguments:
conan lock create . --profile:h=foo -s:h arch=x86 -c myconf=1 --profile_out:h=profile_host_windows_x86.txt
To reproduce the exact build you only need to save a couple of files, I think it is doable, safe, and worth it to decouple it.