Skip to content

Commit 4a9eb8e

Browse files
authored
fixing the update to older revisions existing in cache (#19402)
1 parent 7aed0a8 commit 4a9eb8e

File tree

3 files changed

+106
-10
lines changed

3 files changed

+106
-10
lines changed

conan/internal/graph/proxy.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from conan.internal.graph.graph import (RECIPE_DOWNLOADED, RECIPE_INCACHE, RECIPE_NEWER,
44
RECIPE_NOT_IN_REMOTE, RECIPE_UPDATED, RECIPE_EDITABLE,
55
RECIPE_INCACHE_DATE_UPDATED, RECIPE_UPDATEABLE)
6-
from conan.internal.errors import NotFoundException
6+
from conan.internal.errors import NotFoundException, ConanReferenceAlreadyExistsInDB
77
from conan.errors import ConanException
88

99

@@ -65,19 +65,22 @@ def _get_recipe(self, reference, remotes, update, check_update):
6565
return recipe_layout, status, None
6666

6767
# Something found in remotes, check if we already have the latest in local cache
68-
# TODO: cache2.0 here if we already have a revision in the cache but we add the
69-
# --update argument and we find that same revision in server, we will not
70-
# download anything but we will UPDATE the date of that revision in the
71-
# local cache and WE ARE ALSO UPDATING THE REMOTE
72-
# Check if this is the flow we want to follow
7368
assert ref.timestamp
7469
cache_time = ref.timestamp
7570
if remote_ref.revision != ref.revision:
7671
if cache_time < remote_ref.timestamp:
7772
# the remote one is newer
7873
if should_update_reference(remote_ref, update):
79-
output.info("Retrieving from remote '%s'..." % remote.name)
80-
new_recipe_layout = self._download(remote_ref, remote)
74+
output.info(f"Updating to latest from remote '{remote.name}'...")
75+
try:
76+
new_recipe_layout = self._download(remote_ref, remote)
77+
except ConanReferenceAlreadyExistsInDB:
78+
# When updating to a newer revision in the server, but it already exists
79+
# in the cache with an older timestamp
80+
output.info(f"Latest from '{remote.name}' was found in "
81+
"the cache, using it and updating its timestamp")
82+
new_recipe_layout = self._cache.recipe_layout(remote_ref)
83+
self._cache.update_recipe_timestamp(remote_ref) # make it latest
8184
status = RECIPE_UPDATED
8285
return new_recipe_layout, status, remote
8386
else:

test/integration/cache/cache2_update_test.py

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import copy
2+
import json
3+
import textwrap
24
from collections import OrderedDict
35

46
import pytest
@@ -447,9 +449,9 @@ def test_version_ranges(self):
447449
["libc", {"liba/1.0": "Cache",
448450
"libb/1.0": "Cache"}],
449451
["liba", {"liba/1.1": "Downloaded (default)",
450-
"libb/1.0": "Cache"}],
452+
"libb/1.0": "Cache"}],
451453
["libb", {"liba/1.0": "Cache",
452-
"libb/1.1": "Downloaded (default)"}],
454+
"libb/1.1": "Downloaded (default)"}],
453455
["", {"liba/1.0": "Cache",
454456
"libb/1.0": "Cache"}],
455457
# Patterns not supported, only full name match
@@ -480,3 +482,49 @@ def test_muliref_update_pattern(update, result):
480482
tc.run(f'install --requires="liba/[>=1.0]" --requires="libb/[>=1.0]" -r default {update_flag}')
481483

482484
tc.assert_listed_require(result)
485+
486+
487+
def test_update_remote_older_revision():
488+
# https://github.com/conan-io/conan/issues/19313
489+
c = TestClient(light=True, default_server_user=True)
490+
zlib = textwrap.dedent("""
491+
from conan import ConanFile
492+
class Zlib(ConanFile):
493+
name = "zlib"
494+
version = "1.2.11"
495+
exports_sources = "*"
496+
""")
497+
c.save({"conanfile.py": zlib,
498+
"file.h": "//myheader"})
499+
c.run("export")
500+
c.run("upload * -r=default -c")
501+
502+
c2 = TestClient(light=True, servers=c.servers)
503+
c2.run("graph info --requires=zlib/[*]")
504+
rev1 = "2e87959c586811f8a4eaf12a327cc042"
505+
c2.assert_listed_require({f"zlib/1.2.11#{rev1}": "Downloaded (default)"})
506+
507+
# Modify zlib code
508+
c.save({"file.h": "//myheader 2"})
509+
c.run("export")
510+
c.run("upload * -r=default -c")
511+
512+
c2.run("graph info --requires=zlib/[*] --update")
513+
rev2 = "934b3de03768d9030b61127d588d0a96"
514+
c2.assert_listed_require({f"zlib/1.2.11#{rev2}": "Updated (default)"})
515+
516+
# revert this to old, make it latestlatest
517+
c.save({"file.h": "//myheader"})
518+
c.run("export")
519+
c.run("remove * -r=default -c")
520+
c.run("upload * -r=default -c")
521+
522+
c2.run("graph info --requires=zlib/[*] --update")
523+
assert ("Latest from 'default' was found in "
524+
"the cache, using it and updating its timestamp") in c2.out
525+
c2.assert_listed_require({f"zlib/1.2.11#{rev1}": "Updated (default)"})
526+
527+
c2.run("list *#* --format=json")
528+
revs = json.loads(c2.stdout)["Local Cache"]["zlib/1.2.11"]["revisions"]
529+
# we check that the update from the server has made rev1 the latest in the cache again
530+
assert revs[rev1]["timestamp"] > revs[rev2]["timestamp"]

test/integration/remote/test_local_recipes_index.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,3 +552,48 @@ def build(self):
552552
"requested, but it doesn't match the current available revision in source") in c.out
553553
assert ("ERROR: The 'zlib/1.2.11' package has 'exports_sources' but sources "
554554
"not found in local cache") in c.out
555+
556+
def test_reverting_to_older_revision(self):
557+
# https://github.com/conan-io/conan/issues/19313
558+
folder = temp_folder()
559+
recipes_folder = os.path.join(folder, "recipes")
560+
zlib_config = textwrap.dedent("""
561+
versions:
562+
"1.2.11":
563+
folder: all
564+
""")
565+
zlib = textwrap.dedent("""
566+
from conan import ConanFile
567+
class Zlib(ConanFile):
568+
name = "zlib"
569+
exports_sources = "*"
570+
""")
571+
save_files(recipes_folder,
572+
{"zlib/config.yml": zlib_config,
573+
"zlib/all/conanfile.py": zlib,
574+
"zlib/all/conandata.yml": "",
575+
"zlib/all/file.h": "//myheader"})
576+
577+
c = TestClient(light=True)
578+
c.run(f"remote add local '{folder}'")
579+
c.run("install --requires=zlib/[*] --build=missing")
580+
rev1 = "169da4321a56b77e8538821613a81f1d"
581+
c.assert_listed_require({f"zlib/1.2.11#{rev1}": "Downloaded (local)"})
582+
583+
# Modify zlib code
584+
save_files(recipes_folder, {"zlib/all/file.h": "//myheader 222"})
585+
c.run("install --requires=zlib/[*] --build=missing --update")
586+
rev2 = "8e9fa314a3fd51ab4c930f7e4972f3e7"
587+
c.assert_listed_require({f"zlib/1.2.11#{rev2}": "Updated (local)"})
588+
589+
# Modify zlib code again to a new one
590+
save_files(recipes_folder, {"zlib/all/file.h": "//myheader 333"})
591+
c.run("install --requires=zlib/[*] --update --build=missing")
592+
rev3 = "dd54aebe11b96b3661d8360c68619a72"
593+
c.assert_listed_require({f"zlib/1.2.11#{rev3}": "Updated (local)"})
594+
595+
# Revert to previous one
596+
save_files(recipes_folder, {"zlib/all/file.h": "//myheader"})
597+
c.run("install --requires=zlib/[*] --update --build=missing")
598+
# This crashed https://github.com/conan-io/conan/issues/19313
599+
c.assert_listed_require({f"zlib/1.2.11#{rev1}": "Updated (local)"})

0 commit comments

Comments
 (0)