Skip to content
13 changes: 8 additions & 5 deletions conan/api/model/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,11 +321,14 @@ def items(self) -> Iterable[Tuple[RecipeReference, Dict[PkgReference, Dict]]]:
recipe.timestamp = t
packages = {}
for package_id, pkg_info in rrev_dict.get("packages", {}).items():
prevs = pkg_info.get("revisions", {})
for prev, prev_info in prevs.items():
t = prev_info.get("timestamp")
pref = PkgReference(recipe, package_id, prev, t)
packages[pref] = prev_info
if "revisions" not in pkg_info:
pref = PkgReference(recipe, package_id)
packages[pref] = None
else:
for prev, prev_info in pkg_info["revisions"].items():
t = prev_info.get("timestamp")
pref = PkgReference(recipe, package_id, prev, t)
packages[pref] = prev_info
yield recipe, packages

def recipe_dict(self, ref: RecipeReference):
Expand Down
2 changes: 1 addition & 1 deletion conan/api/subapi/list.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ def find_remotes(self, package_list, remotes):
prevs = self.package_revisions(pref_no_rev, remote=r)
except NotFoundException:
continue
if pref in prevs:
for pref in prevs:
result_pkg_list.add_pref(pref, pkg_info)
if result_pkg_list:
result.add(r.name, result_pkg_list)
Expand Down
9 changes: 5 additions & 4 deletions conan/cli/commands/remove.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,16 @@ def confirmation(message):
result.add_ref(ref)
result.recipe_dict(ref).update(ref_dict) # it doesn't contain "packages"
else:
if not packages: # weird, there is inner package-ids but without prevs
ConanOutput().info(f"No binaries to remove for '{ref.repr_notime()}'")
continue
for pref, pkg_id_info in packages.items():
if not pref.revision:
# Recipe revision is mandatory here, ignore remove request if not present.
ConanOutput().info(f"No binaries to remove for '{ref.repr_notime()}'")
continue
if confirmation(f"Remove the package '{pref.repr_notime()}'?"):
if not args.dry_run:
conan_api.remove.package(pref, remote=remote)
result.add_ref(ref)
result.recipe_dict(ref).update(ref_dict) # it doesn't contain "packages"
result.recipe_dict(ref).update(ref_dict) # it doesn't contain "packages" anymore
result.add_pref(pref, pkg_id_info)
pkg_dict = package_list.package_dict(pref)
result.package_dict(pref).update(pkg_dict)
Expand Down
28 changes: 26 additions & 2 deletions test/integration/command/list/test_combined_pkglist_flows.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,30 @@ def test_graph_2_pkg_list_remotes(self):
assert "app/1.0: Retrieving recipe metadata from remote 'remote2'" in c.out
assert "app/1.0: Retrieving package metadata" in c.out

@pytest.mark.parametrize("list_pattern", ["*#*", "*:*", "*#*:*#*"])
def test_graph_pkg_list_of_recipes_and_binaries(self, list_pattern):
c = TestClient(default_server_user=True, light=True)
c.save({"zlib/conanfile.py": GenConanfile("zlib", "1.0")})
c.run("create zlib")
c.run("upload zlib* -c -r=default")

# Create input pkglist for find-remote
c.run(f"list {list_pattern} --format=json", redirect_stdout="mylist.json")

pkglist_request = json.loads(c.load("mylist.json"))
input_rev = pkglist_request["Local Cache"]["zlib/1.0"]["revisions"]["c570d63921c5f2070567da4bf64ff261"]

c.run("pkglist find-remote mylist.json --format=json --remote default")
pkglist_request = json.loads(c.stdout)
rev = pkglist_request["default"]["zlib/1.0"]["revisions"]["c570d63921c5f2070567da4bf64ff261"]
assert rev, "find-remote shall always list the revision"

if "packages" in input_rev:
assert rev["packages"], "Result does not contain information about binaries"
assert "da39a3ee5e6b4b0d3255bfef95601890afd80709" in rev["packages"]
else:
assert "packages" not in rev, "Result contains information about binaries even if not requested"


class TestPkgListMerge:
""" deep merge lists
Expand Down Expand Up @@ -395,7 +419,7 @@ def test_remove_all(self, client, remote):

@pytest.mark.parametrize("remote", [False, True])
def test_remove_packages_no_revisions(self, client, remote):
# It is necessary to do *#* for actually removing something
# It is necessary to do *#*:*#* for actually removing binaries
remote = "-r=default" if remote else ""
client.run(f"list *#*:* {remote} --format=json", redirect_stdout="pkglist.json")
client.run(f"remove --list=pkglist.json {remote} -c --format=json")
Expand All @@ -408,7 +432,7 @@ def test_remove_packages_no_revisions(self, client, remote):

@pytest.mark.parametrize("remote", [False, True])
def test_remove_packages(self, client, remote):
# It is necessary to do *#* for actually removing something
# It is necessary to do *#*:*#* for actually removing binaries
remote = "-r=default" if remote else ""
client.run(f"list *#*:*#* {remote} --format=json", redirect_stdout="pkglist.json")
client.run(f"remove --list=pkglist.json {remote} -c --dry-run")
Expand Down
Loading