Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement upgrade_only_if_version_changes in manifest #864

Merged
merged 32 commits into from
Sep 3, 2020
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
ebb492f
Add force option in upgrade script
Josue-T Dec 30, 2019
ead80c7
Implement upgrade type management and avoid unusefull upgrade
Josue-T Dec 30, 2019
58cce48
Export old and new version in environnement
Josue-T Apr 11, 2020
640a467
Add helper ynh_compare_package_version
Josue-T Apr 13, 2020
4c5edb5
Merge branch 'stretch-unstable' into abort_if_up_to_date_manifest
Josue-T Apr 13, 2020
3484f73
Clean and syntax
maniackcrudelis Apr 14, 2020
14ef523
Improve env_dict variable in upgrade
Josue-T Apr 14, 2020
3d51e23
Add comments
Josue-T Apr 14, 2020
fec5d3d
Rename variable
Josue-T Apr 14, 2020
17e8bde
Rename heper
Josue-T Apr 14, 2020
5315807
Cleanup comment
Josue-T Apr 14, 2020
3578588
Replace actual by current
Josue-T Apr 15, 2020
f416b94
Put upgrade_only_if_version_changes in integration section
Josue-T Apr 15, 2020
d947724
Fix typo
Josue-T Apr 15, 2020
ceeb34f
Use 'dpkg --compare-versions'
Josue-T Apr 15, 2020
8dd3986
Fix rename variable
Josue-T Apr 15, 2020
4f0d5ce
Improve version management in '_app_upgradable'
Josue-T Apr 15, 2020
a096a36
Also manage downgrade
Josue-T Apr 15, 2020
9389f46
simplification
yalh76 Apr 15, 2020
e7970d8
Check settings 'upgrade_only_if_version_changes' before to check upda…
Josue-T Apr 23, 2020
1826e3c
Make more robust version management in upgrade
Josue-T Apr 23, 2020
c34de0b
Improve version management in catalog
Josue-T Apr 24, 2020
ce6c33a
Fix version key in installed version
Josue-T Apr 27, 2020
f2791c9
Make more rebobut version check
Josue-T Apr 27, 2020
01d5c91
Simply code
Josue-T Apr 27, 2020
72b412c
Cleanup code indentation
Josue-T Apr 27, 2020
e01859f
Fix tests
alexAubin Apr 27, 2020
5c6b411
Add comment about dependances
Josue-T May 2, 2020
95b7885
Merge remote-tracking branch 'upstream/stretch-unstable' into abort_i…
Josue-T May 2, 2020
8d2bde8
Install python-packaging as dependance
Josue-T May 3, 2020
7c6748e
Merge branch '4.1' into abort_if_up_to_date_manifest
Josue-T Aug 18, 2020
3612ac4
Enable this behavior by default (no need to enable the option in the …
alexAubin Aug 31, 2020
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
4 changes: 4 additions & 0 deletions data/actionsmap/yunohost.yml
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,10 @@ app:
-f:
full: --file
help: Folder or tarball for upgrade
-F:
full: --force
help: Force the update, even though the app is up to date
action: store_true
Copy link
Member

Choose a reason for hiding this comment

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

I suggest a break change:

-f is used in install operation as in other part of the cli. I suggest to define -F for --file and -f for --force.

This change concerns packagers, and i prefer a break change for packager, than an inconsistency for final users

Copy link
Member

Choose a reason for hiding this comment

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

N.B. : it's used here : https://github.com/YunoHost/package_check/blob/master/sub_scripts/testing_process.sh#L965 so gotta be careful

I'm okay with the change but maybe we can do this in a separate PR to move forward ...


### app_change_url()
change-url:
Expand Down
52 changes: 48 additions & 4 deletions data/helpers.d/utils
Original file line number Diff line number Diff line change
Expand Up @@ -411,8 +411,7 @@ ynh_app_upstream_version () {
# Manage arguments with getopts
ynh_handle_getopts_args "$@"

manifest="${manifest:-../manifest.json}"
version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
version_key=$YNH_APP_MANIFEST_VERSION
echo "${version_key/~ynh*/}"
}

Expand All @@ -435,8 +434,7 @@ ynh_app_package_version () {
# Manage arguments with getopts
ynh_handle_getopts_args "$@"

manifest="${manifest:-../manifest.json}"
version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
version_key=$YNH_APP_MANIFEST_VERSION
echo "${version_key/*~ynh/}"
}

Expand Down Expand Up @@ -487,3 +485,49 @@ ynh_check_app_version_changed () {
fi
echo $return_value
}

# Compare the current package version against another version given as an argument.
# This is really useful when we need to do some actions only for some old package versions.
#
# example: ynh_compare_current_package_version --comparison lt --version 2.3.2~ynh1
# This example will check if the installed version is lower than (lt) the version 2.3.2~ynh1
#
# Generally you might probably use it as follow in the upgrade script
#
# if ynh_compare_current_package_version --comparaison lt --version 2.3.2~ynh1
# then
# # Do something that is needed for the package version older than 2.3.2~ynh1
Josue-T marked this conversation as resolved.
Show resolved Hide resolved
# fi
#
# usage: ynh_compare_current_package_version --comparison lt|le|eq|ne|ge|gt
# | arg: --comparison - Comparison type. Could be : lt (lower than), le (lower or equal),
# | eq (equal), ne (not equal), ge (greater or equal), gt (greater than)
# | arg: --version - The version to compare. Need to be a version in the yunohost package version type (like 2.3.1~ynh4)
#
# Return 0 if the evaluation is true. 1 if false.
#
# Requires YunoHost version 3.8.0 or higher.
ynh_compare_current_package_version() {
local legacy_args=cv
declare -Ar args_array=( [c]=comparison= [v]=version= )
local version
local comparison
# Manage arguments with getopts
ynh_handle_getopts_args "$@"

local current_version=$YNH_APP_CURRENT_VERSION

# Check the syntax of the versions
if [[ ! $version =~ '~ynh' ]] || [[ ! $current_version =~ '~ynh' ]]
then
ynh_die "Invalid argument for version."
fi

# Check validity of the comparator
if [[ ! $comparison =~ (lt|le|eq|ne|ge|gt) ]]; then
ynh_die "Invialid comparator must be : lt, le, eq, ne, ge, gt"
fi

# Return the return value of dpkg --compare-versions
dpkg --compare-versions $current_version $comparison $version
}
61 changes: 58 additions & 3 deletions src/yunohost/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,24 @@ def app_info(app, full=False):


def _app_upgradable(app_infos):
from packaging import version
alexAubin marked this conversation as resolved.
Show resolved Hide resolved
alexAubin marked this conversation as resolved.
Show resolved Hide resolved

# Determine upgradability
# In case there is neither update_time nor install_time, we assume the app can/has to be upgraded

if not app_infos.get("from_catalog", None):
# Firstly use the version to know if an upgrade is available
app_is_in_catalog = bool(app_infos.get("from_catalog"))
upgrade_only_if_version_changes = app_infos["manifest"].get('integration', {}).get("upgrade_only_if_version_changes", None) is True
installed_version = version.parse(app_infos.get("version", "0~ynh0"))
version_in_catalog = version.parse(app_infos.get("from_catalog", {}).get("manifest", {}).get("version", "0~ynh0"))

if app_is_in_catalog and '~ynh' in str(installed_version) and '~ynh' in str(version_in_catalog):
if upgrade_only_if_version_changes and installed_version < version_in_catalog:
return "yes"
else:
return "no"

if not app_is_in_catalog:
return "url_required"
if not app_infos["from_catalog"].get("lastUpdate") or not app_infos["from_catalog"].get("git"):
return "url_required"
Expand Down Expand Up @@ -347,6 +360,7 @@ def app_change_url(operation_logger, app, domain, path):
env_dict["YNH_APP_ID"] = app_id
env_dict["YNH_APP_INSTANCE_NAME"] = app
env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb)
env_dict["YNH_APP_MANIFEST_VERSION"] = manifest.get("version", "?")

env_dict["YNH_APP_OLD_DOMAIN"] = old_domain
env_dict["YNH_APP_OLD_PATH"] = old_path
Expand Down Expand Up @@ -410,7 +424,7 @@ def app_change_url(operation_logger, app, domain, path):
hook_callback('post_app_change_url', args=args_list, env=env_dict)


def app_upgrade(app=[], url=None, file=None):
def app_upgrade(app=[], url=None, file=None, force=False):
"""
Upgrade app

Expand All @@ -420,6 +434,7 @@ def app_upgrade(app=[], url=None, file=None):
url -- Git url to fetch for upgrade

"""
from packaging import version
from yunohost.hook import hook_add, hook_remove, hook_exec, hook_callback
from yunohost.permission import permission_sync_to_user

Expand Down Expand Up @@ -459,12 +474,46 @@ def app_upgrade(app=[], url=None, file=None):
elif app_dict["upgradable"] == "url_required":
logger.warning(m18n.n('custom_app_url_required', app=app_instance_name))
continue
elif app_dict["upgradable"] == "yes":
elif app_dict["upgradable"] == "yes" or force:
manifest, extracted_app_folder = _fetch_app_from_git(app_instance_name)
else:
logger.success(m18n.n('app_already_up_to_date', app=app_instance_name))
continue

# Manage upgrade type and avoid any upgrade if there is nothing to do
upgrade_type = "UNKNOWN"
upgrade_only_if_version_changes = manifest.get('integration', {}).get("upgrade_only_if_version_changes", None) is True
# Get current_version and new version
app_new_version = version.parse(manifest.get("version", "?"))
app_current_version = version.parse(app_dict.get("version", "?"))
if "~ynh" not in str(app_current_version) or "~ynh" not in str(app_new_version):
logger.warning("/!\\ Packagers ! You have enabled the setting 'upgrade_only_if_version_changes' but you haven't used the official way to define the package version")
upgrade_only_if_version_changes = False
if upgrade_only_if_version_changes:
if app_current_version >= app_new_version and not force:
# In case of upgrade from file or custom repository
# No new version available
logger.success(m18n.n('app_already_up_to_date', app=app_instance_name))
Josue-T marked this conversation as resolved.
Show resolved Hide resolved
# Save update time
now = int(time.time())
app_setting(app_instance_name, 'update_time', now)
app_setting(app_instance_name, 'current_revision', manifest.get('remote', {}).get('revision', "?"))
continue
elif app_current_version > app_new_version:
kay0u marked this conversation as resolved.
Show resolved Hide resolved
upgrade_type = "DOWNGRADE_FORCED"
elif app_current_version == app_new_version:
upgrade_type = "UPGRADE_FORCED"
else:
app_current_version_upstream, app_current_version_pkg = str(app_current_version).split("~ynh")
app_new_version_upstream, app_new_version_pkg = str(app_new_version).split("~ynh")
if app_current_version_upstream == app_new_version_upstream:
upgrade_type = "UPGRADE_PACKAGE"
elif app_current_version_pkg == app_new_version_pkg:
upgrade_type = "UPGRADE_APP"
else:
upgrade_type = "UPGRADE_FULL"
Josue-T marked this conversation as resolved.
Show resolved Hide resolved


# Check requirements
_check_manifest_requirements(manifest, app_instance_name=app_instance_name)
_assert_system_is_sane_for_app(manifest, "pre")
Expand All @@ -483,6 +532,9 @@ def app_upgrade(app=[], url=None, file=None):
env_dict["YNH_APP_ID"] = app_id
env_dict["YNH_APP_INSTANCE_NAME"] = app_instance_name
env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb)
env_dict["YNH_APP_UPGRADE_TYPE"] = upgrade_type
env_dict["YNH_APP_MANIFEST_VERSION"] = str(app_new_version)
env_dict["YNH_APP_CURRENT_VERSION"] = str(app_current_version)

# Start register change on system
related_to = [('app', app_instance_name)]
Expand Down Expand Up @@ -695,6 +747,7 @@ def confirm_install(confirm):
env_dict["YNH_APP_ID"] = app_id
env_dict["YNH_APP_INSTANCE_NAME"] = app_instance_name
env_dict["YNH_APP_INSTANCE_NUMBER"] = str(instance_number)
env_dict["YNH_APP_MANIFEST_VERSION"] = manifest.get("version", "?")

# Start register change on system
operation_logger.extra.update({'env': env_dict})
Expand Down Expand Up @@ -803,6 +856,7 @@ def confirm_install(confirm):
env_dict_remove["YNH_APP_ID"] = app_id
env_dict_remove["YNH_APP_INSTANCE_NAME"] = app_instance_name
env_dict_remove["YNH_APP_INSTANCE_NUMBER"] = str(instance_number)
env_dict["YNH_APP_MANIFEST_VERSION"] = manifest.get("version", "?")

# Execute remove script
operation_logger_remove = OperationLogger('remove_on_failed_install',
Expand Down Expand Up @@ -980,6 +1034,7 @@ def app_remove(operation_logger, app):
env_dict["YNH_APP_ID"] = app_id
env_dict["YNH_APP_INSTANCE_NAME"] = app
env_dict["YNH_APP_INSTANCE_NUMBER"] = str(app_instance_nb)
env_dict["YNH_APP_MANIFEST_VERSION"] = manifest.get("version", "?")
operation_logger.extra.update({'env': env_dict})
operation_logger.flush()

Expand Down