Skip to content

Commit cbea050

Browse files
authored
improve pkglist find-remote management of partial information (#19265)
1 parent bead42a commit cbea050

File tree

2 files changed

+149
-17
lines changed

2 files changed

+149
-17
lines changed

conan/api/subapi/list.py

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import copy
21
import os
32
from collections import OrderedDict
43
from typing import Dict
@@ -318,27 +317,50 @@ def find_remotes(self, package_list, remotes):
318317
(Experimental) Find the remotes where the current package lists can be found
319318
"""
320319
result = MultiPackagesList()
320+
app = ConanBasicApp(self._conan_api)
321321
for r in remotes:
322322
result_pkg_list = PackagesList()
323-
for ref, packages in package_list.items():
324-
ref_no_rev = copy.copy(ref) # TODO: Improve ugly API
325-
ref_no_rev.revision = None
323+
for ref, ref_contents in package_list.serialize().items():
324+
ref = RecipeReference.loads(ref)
326325
try:
327-
revs = self.recipe_revisions(ref_no_rev, remote=r)
326+
remote_rrevs = app.remote_manager.get_recipe_revisions(ref, remote=r)
328327
except NotFoundException:
329328
continue
330-
if ref not in revs: # not found
329+
revisions = ref_contents.get("revisions")
330+
if revisions is None: # This is a package list just with name/version
331+
if remote_rrevs:
332+
result_pkg_list.add_ref(ref)
331333
continue
332-
result_pkg_list.add_ref(ref)
333-
for pref, pkg_info in packages.items():
334-
pref_no_rev = copy.copy(pref) # TODO: Improve ugly API
335-
pref_no_rev.revision = None
336-
try:
337-
prevs = self.package_revisions(pref_no_rev, remote=r)
338-
except NotFoundException:
334+
335+
for revision, rev_content in revisions.items():
336+
ref.revision = revision
337+
# We look for the value of revision in server, to return timestamp too
338+
found = next((r for r in remote_rrevs if r == ref), None)
339+
if not found:
339340
continue
340-
if pref in prevs:
341-
result_pkg_list.add_pref(pref, pkg_info)
341+
result_pkg_list.add_ref(found)
342+
packages = rev_content.get("packages")
343+
if packages is None:
344+
continue
345+
for pkgid, pkgcontent in packages.items():
346+
pref = PkgReference(ref, pkgid)
347+
try:
348+
remote_prefs = app.remote_manager.get_package_revisions(pref, remote=r)
349+
except NotFoundException:
350+
continue
351+
pkg_revisions = pkgcontent.get("revisions")
352+
if pkg_revisions is None: # This is a package_id, no prevs
353+
if remote_prefs:
354+
result_pkg_list.add_pref(pref, pkgcontent.get("info"))
355+
continue
356+
for pkg_revision, prev_content in pkg_revisions.items():
357+
pref.revision = pkg_revision
358+
# We look for the value of revision in server, to return timestamp too
359+
pfound = next((r for r in remote_prefs if r == pref), None)
360+
if not pfound:
361+
continue
362+
result_pkg_list.add_pref(pfound, pkgcontent.get("info"))
363+
342364
if result_pkg_list:
343365
result.add(r.name, result_pkg_list)
344366
return result

test/integration/command/list/test_combined_pkglist_flows.py

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import pytest
55

66
from conan.test.assets.genconanfile import GenConanfile
7+
from conan.test.utils.env import environment_update
78
from conan.test.utils.tools import TestClient, TestServer
89

910

@@ -214,6 +215,115 @@ def test_graph_2_pkg_list_remotes(self):
214215
assert "app/1.0: Retrieving recipe metadata from remote 'remote2'" in c.out
215216
assert "app/1.0: Retrieving package metadata" in c.out
216217

218+
def test_input_only_name_version(self):
219+
c = TestClient(default_server_user=True, light=True)
220+
c.save({"zlib/conanfile.py": GenConanfile("zlib", "1.0")})
221+
c.run("create zlib")
222+
c.run("upload zlib* -c -r=default")
223+
224+
# Create input pkglist for find-remote
225+
c.run(f"list * --format=json", redirect_stdout="mylist.json")
226+
pkglist = json.loads(c.load("mylist.json"))
227+
expected = {"zlib/1.0": {}}
228+
assert pkglist["Local Cache"] == expected
229+
230+
c.run("pkglist find-remote mylist.json --format=json --remote default")
231+
pkglist = json.loads(c.stdout)
232+
assert pkglist["default"] == expected
233+
234+
def test_input_recipe_revisions(self):
235+
c = TestClient(default_server_user=True, light=True)
236+
c.save({"zlib/conanfile.py": GenConanfile("zlib", "1.0")})
237+
c.run("create zlib")
238+
c.run("upload zlib* -c -r=default")
239+
240+
# Create input pkglist for find-remote
241+
c.run(f"list *#* --format=json", redirect_stdout="mylist.json")
242+
243+
def _check(origin):
244+
pkglist = json.loads(c.load("mylist.json"))
245+
revs = pkglist[origin]["zlib/1.0"]["revisions"]
246+
assert list(revs) == ["c570d63921c5f2070567da4bf64ff261"]
247+
assert "packages" not in revs["c570d63921c5f2070567da4bf64ff261"]
248+
249+
_check("Local Cache")
250+
251+
c.run("pkglist find-remote mylist.json --format=json --remote default",
252+
redirect_stdout="mylist.json")
253+
_check("default")
254+
255+
def test_input_only_package_ids(self):
256+
c = TestClient(default_server_user=True, light=True)
257+
c.save({"zlib/conanfile.py": GenConanfile("zlib", "1.0").with_settings("os")})
258+
c.run("create zlib -s os=Linux")
259+
c.run("upload zlib* -c -r=default")
260+
261+
# Create input pkglist for find-remote
262+
c.run(f"list *:* --format=json", redirect_stdout="mylist.json")
263+
264+
def _check(origin):
265+
pkglist = json.loads(c.load("mylist.json"))
266+
revs = pkglist[origin]["zlib/1.0"]["revisions"]
267+
assert list(revs) == ["1cb7410d0365f87510a6767c7bef804e"]
268+
info = {"info": {'settings': {'os': 'Linux'}}}
269+
expected = {"9a4eb3c8701508aa9458b1a73d0633783ecc2270": info}
270+
assert revs["1cb7410d0365f87510a6767c7bef804e"]["packages"] == expected
271+
272+
c.run("pkglist find-remote mylist.json --format=json --remote default",
273+
redirect_stdout="mylist.json")
274+
_check("default")
275+
276+
def test_graph_pkg_list_of_recipes_and_binaries(self):
277+
c = TestClient(default_server_user=True, light=True)
278+
c.save({"zlib/conanfile.py": GenConanfile("zlib", "1.0").with_settings("os")})
279+
c.run("create zlib -s os=Linux")
280+
c.run("upload zlib* -c -r=default")
281+
282+
# Create input pkglist for find-remote
283+
c.run(f"list *#*:*#* --format=json", redirect_stdout="mylist.json")
284+
285+
def _check(origin):
286+
pkglist = json.loads(c.load("mylist.json"))
287+
revs = pkglist[origin]["zlib/1.0"]["revisions"]
288+
assert list(revs) == ["1cb7410d0365f87510a6767c7bef804e"]
289+
expected = {'settings': {'os': 'Linux'}}
290+
pkgs = revs["1cb7410d0365f87510a6767c7bef804e"]["packages"]
291+
assert list(pkgs) == ["9a4eb3c8701508aa9458b1a73d0633783ecc2270"]
292+
pkg = pkgs["9a4eb3c8701508aa9458b1a73d0633783ecc2270"]
293+
assert pkg["info"] == expected
294+
assert list(pkg["revisions"]) == ["1d3c57385f4133c1fbd6d13bd538496e"]
295+
296+
_check("Local Cache")
297+
c.run("pkglist find-remote mylist.json --format=json --remote default",
298+
redirect_stdout="mylist.json")
299+
_check("default")
300+
301+
def test_graph_pkg_list_counter_example(self):
302+
c = TestClient(default_server_user=True, light=True)
303+
c.save({"conanfile.py": GenConanfile("zlib", "1.0").with_package_file("file.txt",
304+
env_var="MY_VAR")})
305+
306+
with environment_update({"MY_VAR": "1"}):
307+
c.run("create .")
308+
with environment_update({"MY_VAR": "2"}):
309+
c.run("create .")
310+
c.run("upload zlib*:*#* -c -r=default")
311+
312+
# Create input pkglist for find-remote
313+
c.run(f"list zlib/1.0#latest:*#latest --format=json", redirect_stdout="mylist.json")
314+
315+
def _check(origin):
316+
pkglist = json.loads(c.load("mylist.json"))
317+
prevs = pkglist[origin]["zlib/1.0"]["revisions"]
318+
input_pkgs = prevs["212b9babae6a4b8a8362703cec4257ad"]["packages"]
319+
prevs = input_pkgs["da39a3ee5e6b4b0d3255bfef95601890afd80709"]["revisions"]
320+
assert len(prevs) == 1
321+
322+
_check("Local Cache")
323+
c.run("pkglist find-remote mylist.json --format=json --remote default",
324+
redirect_stdout="mylist.json")
325+
_check("default")
326+
217327

218328
class TestPkgListMerge:
219329
""" deep merge lists
@@ -395,7 +505,7 @@ def test_remove_all(self, client, remote):
395505

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

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

0 commit comments

Comments
 (0)