Skip to content

Commit

Permalink
Ignore patch version in upgrade scenarios
Browse files Browse the repository at this point in the history
  • Loading branch information
ichorid committed Jan 15, 2021
1 parent 176ba77 commit da11361
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import filecmp
import json
import os
from distutils.version import LooseVersion

from tribler_common.simpledefs import (
STATEDIR_CHANNELS_DIR,
Expand All @@ -14,6 +15,7 @@
VersionHistory,
copy_state_directory,
fork_state_directory_if_necessary,
must_upgrade,
version_to_dirname,
)
from tribler_core.utilities.path_util import Path
Expand Down Expand Up @@ -60,12 +62,14 @@ def test_get_last_upgradable_version_based_on_dir(tmpdir):
json_dict = {"last_version": "100.1.1", "history": dict()}
json_dict["history"]["1"] = "100.1.1" # no dir - bad
json_dict["history"]["2"] = "99.2.3" # dir in place, earlier than 3 - bad
(root_state_dir / "102.1").mkdir()
json_dict["history"]["3"] = "102.1.0" # version OK, got dir, same major/minor version as us - ignore
(root_state_dir / "99.2").mkdir()
json_dict["history"]["3"] = "92.3.4" # dir in place, more recent than 2, - good
json_dict["history"]["4"] = "92.3.4" # dir in place, more recent than 2, - good
(root_state_dir / "92.3").mkdir()
json_dict["history"]["4"] = "200.2.3" # version higher than code version
json_dict["history"]["5"] = "200.2.3" # version higher than code version
(root_state_dir / "200.2").mkdir()
json_dict["history"]["5"] = "94.3.4" # version OK, no dir - bad
json_dict["history"]["6"] = "94.3.4" # version OK, no dir - bad

(root_state_dir / VERSION_HISTORY_FILE).write_text(json.dumps(json_dict))

Expand All @@ -74,6 +78,22 @@ def test_get_last_upgradable_version_based_on_dir(tmpdir):
assert last_upgradable_version == "92.3.4"


def test_must_upgrade():
"""
By convention, we only upgrade if the previous version's major/minor is lower than the new version's.
This is another way to say that we ignore the patch version for upgrade purposes.
"""
assert must_upgrade(LooseVersion("1.2.3"), LooseVersion("1.3.3"))
assert must_upgrade(LooseVersion("1.2.3"), LooseVersion("2.3.3"))
assert must_upgrade(LooseVersion("1.2.3"), LooseVersion("2.4.3"))
assert must_upgrade(LooseVersion("1.2.3"), LooseVersion("2.1.3"))
assert not must_upgrade(LooseVersion("1.2.3"), LooseVersion("1.2.3"))
assert not must_upgrade(LooseVersion("1.2.3"), LooseVersion("1.2.4"))
assert not must_upgrade(LooseVersion("1.3.3"), LooseVersion("1.2.4"))
assert not must_upgrade(LooseVersion("2.3.3"), LooseVersion("2.3.4"))
assert not must_upgrade(LooseVersion("2.3.3"), LooseVersion("1.4.4"))


def test_fork_state_directory(tmpdir_factory):
from tribler_core.upgrade import version_manager

Expand Down
21 changes: 19 additions & 2 deletions src/tribler-core/tribler_core/upgrade/version_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,23 @@
Note that due to failures in design pre-7.4 series and 7.4.x series get special treatment.
"""

def must_upgrade(old_ver:LooseVersion, new_ver:LooseVersion):
"""
This function compares two LooseVersions by combination of major/minor components only, omitting the patch version.
By convention, in Tribler we only fork version directories on major/minor version changes, and never touch
the directory format in patch versions.
e.g 1.2.3 -> 1.3.0 must upgrade (return True)
but 1.2.3 -> 1.2.4 must not upgrade (return False)
:param old_ver: the version to upgrade from
:param new_ver: the version to upgrade to
:return: True, if new_ver's major/minor version is higher than old_ver's major/minor version, otherwise False
"""
major_version_is_greater = new_ver.version[0] > old_ver.version[0]
major_version_is_equal = new_ver.version[0] == old_ver.version[0]
minor_version_is_greater = new_ver.version[1] > old_ver.version[1]

return major_version_is_greater or (major_version_is_equal and minor_version_is_greater)

class VersionHistory:
"""
Expand Down Expand Up @@ -83,14 +100,14 @@ def update(self, version_id):
def get_last_upgradable_version(self, root_state_dir, code_version):
"""
This function gets the list of previously used Tribler versions from the usage history file
and returns the most recently used version that has lower number than the code version.
and returns the most recently used version that has lower major/minor number than the code version.
:param root_state_dir: root state directory, where the version history file and old version dirs
:param code_version: current code version
:return: None if no upgradable version found, version number otherwise
"""

for version in [version for _, version in sorted(self.version_history["history"].items(), reverse=True)]:
if (LooseVersion(code_version) > LooseVersion(version)
if (must_upgrade(LooseVersion(version), LooseVersion(code_version))
and get_versioned_state_directory(root_state_dir, version).exists()):
return version
return None
Expand Down

0 comments on commit da11361

Please sign in to comment.