Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion conan/cli/commands/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def lock_add(conan_api, parser, subparser, *args):
Add requires, build-requires or python-requires to an existing or new lockfile.
The resulting lockfile will be ordered, newer versions/revisions first.
References can be supplied with and without revisions like "--requires=pkg/version",
but they must be package references, including at least the version,
but they must be recipe references, including at least the version,
and they cannot contain a version range.
"""
subparser.add_argument('--requires', action="append", help='Add references to lockfile.')
Expand Down
2 changes: 1 addition & 1 deletion conan/internal/graph/graph_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ def _resolved_system(node, require, profile_build, profile_host, resolve_prerele
elif require.ref.version == d.version:
if d.revision is None or require.ref.revision is None or \
d.revision == require.ref.revision:
require.ref.revision = d.revision
require.ref.revision = d.revision or "platform"
layout = BasicLayout(require.ref, None)
return layout, ConanFile(str(d)), RECIPE_PLATFORM, None

Expand Down
60 changes: 58 additions & 2 deletions test/integration/graph/test_platform_requires.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ def test_platform_requires_build_context(self):
"pkg/conanfile.py": GenConanfile("pkg", "1.0").with_tool_requires("tool/1.0"),
"profile": "[settings]\nos=Linux\n[platform_requires]\ndep/1.0"})
client.run("create tool -pr:b=profile --build-require")
assert "dep/1.0 - Platform" in client.out
assert "dep/1.0#platform - Platform" in client.out
client.run("create pkg -pr:b=profile")
assert "dep/1.0 - Platform" in client.out
assert "dep/1.0#platform - Platform" in client.out

def test_graph_info_platform_requires_range(self):
"""
Expand Down Expand Up @@ -194,6 +194,62 @@ def test_platform_requires_range(self):
c.run("install . -pr=profile", assert_error=True)
assert "ERROR: Requirement 'dep/1.2' not in lockfile" in c.out

@pytest.mark.parametrize("platform_rev", [None, "myrev"])
@pytest.mark.parametrize("is_tool_platform", [True, False])
def test_platform_requires_lockfile(self, platform_rev, is_tool_platform):
tc = TestClient(light=True)
profile_rev = f"#{platform_rev}" if platform_rev else ""
expected_rev = platform_rev if platform_rev else "platform"
conanfile = GenConanfile("pkg", "1.0")
if is_tool_platform:
conanfile = conanfile.with_tool_requires("dep/1.0")
else:
conanfile = conanfile.with_requirement("dep/1.0")
substitution = "platform_tool_requires" if is_tool_platform else "platform_requires"
tc.save({"dep/conanfile.py": GenConanfile("dep", "1.0"),
"conanfile.py": conanfile,
"profile": f"[{substitution}]\ndep/1.0{profile_rev}"})
tc.run("create dep")
created_dep_ref = tc.created_layout().reference.ref

# The platform revision is correctly captured in the lockfile
tc.run("lock create --lockfile-out=platform.lock -pr=profile")
assert f"dep/1.0#{expected_rev}" in tc.load("platform.lock")
tc.run("lock create --lockfile-out=real.lock")
assert str(created_dep_ref) in tc.load("real.lock")

# Not using lockfiles when expanding the graph works as expected
tc.run("install")
tc.assert_listed_require({str(created_dep_ref): "Cache"}, build=is_tool_platform)
tc.run("install -pr=profile")
tc.assert_listed_require({f"dep/1.0#{expected_rev}": "Platform"}, build=is_tool_platform)

# And also with lockfiles, the platform revision is correctly captured in the lockfile
tc.run("install --lockfile=real.lock")
tc.assert_listed_require({str(created_dep_ref): "Cache"}, build=is_tool_platform)
tc.run("install -pr=profile --lockfile=platform.lock")
tc.assert_listed_require({f"dep/1.0#{expected_rev}": "Platform"}, build=is_tool_platform)

tc.run("install --lockfile=platform.lock", assert_error=True)
assert "Package 'dep/1.0' not resolved" in tc.out
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if this error should use repr_notime() internally to show the revision if available?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but maybe unrelated ,so better in another PR?

tc.run("install -pr=profile --lockfile=real.lock", assert_error=True)
assert f"Requirement 'dep/1.0#{expected_rev}' not in lockfile" in tc.out

# Now, what happens if we just merge both lockfiles so we can switch on the fly?
# Both can coexist because they have different revisions.
# The platform requires does not have a timestamp, so it's never selected outside platform matches
tc.run("lock merge --lockfile=real.lock --lockfile=platform.lock --lockfile-out=merged.lock")
tc.run("install --lockfile=merged.lock")
tc.assert_listed_require({str(created_dep_ref): "Cache"}, build=is_tool_platform)
tc.run("install -pr=profile --lockfile=merged.lock")
tc.assert_listed_require({f"dep/1.0#{expected_rev}": "Platform"}, build=is_tool_platform)

# And now, having a lockfile which just has name/version
requires = "build-requires" if is_tool_platform else "requires"
tc.run(f"lock add --{requires}=dep/1.0 --lockfile-out=simple.lock")
tc.run("install -pr=profile --lockfile=simple.lock")
tc.assert_listed_require({f"dep/1.0#{expected_rev}": "Platform"}, build=is_tool_platform)


class TestGenerators:
def test_platform_requires_range(self):
Expand Down
Loading