Merge pull request #864 from YunoHost/abort_if_up_to_date_manifest

Implement `upgrade_only_if_version_changes` in manifest
This commit is contained in:
Alexandre Aubin 2020-09-03 15:51:47 +02:00 committed by GitHub
commit b869f3a7d7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 104 additions and 7 deletions

View file

@ -660,6 +660,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
### app_change_url()
change-url:

View file

@ -436,9 +436,8 @@ ynh_app_upstream_version () {
local manifest
# 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*/}"
}
@ -461,9 +460,8 @@ ynh_app_package_version () {
local manifest
# 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/}"
}
@ -516,3 +514,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
# 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
}

View file

@ -184,11 +184,21 @@ def app_info(app, full=False):
def _app_upgradable(app_infos):
from packaging import version
# 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"))
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 installed_version < version_in_catalog:
return "yes"
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"
@ -378,6 +388,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
@ -441,7 +452,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
@ -451,6 +462,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
from yunohost.regenconf import manually_modified_files
@ -491,12 +503,41 @@ 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"
# 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" in str(app_current_version) and "~ynh" in str(app_new_version):
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))
# 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:
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"
# Check requirements
_check_manifest_requirements(manifest, app_instance_name=app_instance_name)
_assert_system_is_sane_for_app(manifest, "pre")
@ -515,6 +556,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)
# We'll check that the app didn't brutally edit some system configuration
manually_modified_files_before_install = manually_modified_files()
@ -745,6 +789,9 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu
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})
# We'll check that the app didn't brutally edit some system configuration
@ -854,6 +901,7 @@ def app_install(operation_logger, app, label=None, args=None, no_remove_on_failu
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',
@ -1050,6 +1098,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()