Skip to content

Commit

Permalink
Read release versions dynamically from filesystem
Browse files Browse the repository at this point in the history
Check the existing files on download.geany.org to determine which
is the latest version and use this instead of the globally stored
latest version.
This enables us to add in-release sub versions.
  • Loading branch information
eht16 committed Mar 22, 2020
1 parent d48d5cc commit 23e8033
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 5 deletions.
1 change: 1 addition & 0 deletions README.dev.md
Expand Up @@ -103,6 +103,7 @@ the settings to your needs:

LOGGING['handlers']['file']['filename'] = '/tmp/geany_django.log'

LATEST_VERSION_RELEASES_DIRECTORY = '/path/to/geany/releases/directory/or/just/empty'
STATIC_DOCS_GEANY_SOURCE_TARBALL = '/path/to/geany/source/tarball/or/just/empty'
IRC_USER_LIST_FILE = '/path/to/irc/data/or/just/empty'

Expand Down
2 changes: 2 additions & 0 deletions docker/local_settings.docker.py
Expand Up @@ -55,6 +55,8 @@
STATIC_DOCS_GEANY_DESTINATION_URL = os.path.join(MEDIA_URL, 'i18n')
STATIC_DOCS_GEANY_I18N_STATISTICS_FILENAME = 'i18n_statistics.json'

LATEST_VERSION_RELEASES_DIRECTORY = ''

LOGGING = {
'version': 1,
'disable_existing_loggers': True,
Expand Down
2 changes: 2 additions & 0 deletions geany/settings.py
Expand Up @@ -456,6 +456,8 @@

IRC_USER_LIST_FILE = '/srv/tmp/irc_userlist'

LATEST_VERSION_RELEASES_DIRECTORY = '/srv/www/download.geany.org'

MEZZANINE_SYNC_PAGES_DESTINATION_PATH = os.path.join(PROJECT_ROOT, 'page_content')


Expand Down
13 changes: 12 additions & 1 deletion latest_version/context_processors.py
Expand Up @@ -12,12 +12,23 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from mezzanine.conf import settings

from geany.decorators import cache_function, CACHE_TIMEOUT_1HOUR
from latest_version.models import LatestVersion
from latest_version.releases import ReleaseVersionsProvider


# ----------------------------------------------------------------------
@cache_function(CACHE_TIMEOUT_1HOUR, ignore_arguments=True)
def latest_version(request):
geany_latest_version = LatestVersion.objects.get(id=1)
return dict(geany_latest_version=geany_latest_version)

release_versions_provider = ReleaseVersionsProvider(
settings.LATEST_VERSION_RELEASES_DIRECTORY,
fallback_version=geany_latest_version.version)
release_versions = release_versions_provider.provide()

return dict(
geany_latest_version=geany_latest_version,
release_versions=release_versions)
133 changes: 133 additions & 0 deletions latest_version/releases.py
@@ -0,0 +1,133 @@
# -*- coding: utf-8 -*-
# LICENCE: This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from pathlib import Path
import logging
import re

from packaging.version import parse as parse_version


RELEASE_TYPE_SOURCE_GZIP = 'source_gzip_version'
RELEASE_TYPE_SOURCE_BZIP2 = 'source_bzip2_version'
RELEASE_TYPE_WINDOWS = 'windows_version'
RELEASE_TYPE_MACOS = 'macos_version'

RELEASE_TYPES = {
RELEASE_TYPE_SOURCE_GZIP: {
'pattern': re.compile(r'^geany-([0-9\.\-]+).tar.gz$'),
'fallback_filename': 'geany-{version}.tar.gz'
},
RELEASE_TYPE_SOURCE_BZIP2: {
# ~'pattern': re.compile(r'^geany-([0-9\.\-]+).tar.bz2$'),
'pattern': re.compile(r'^gany-([0-9\.\-]+).tar.bz2$'),
'fallback_filename': 'geany-{version}.tar.bz2'
},
RELEASE_TYPE_WINDOWS: {
'pattern': re.compile(r'^geany-([0-9\.\-]+)_setup(-[0-9]+)?.exe$'),
'fallback_filename': 'geany-{version}_setup.exe'
},
RELEASE_TYPE_MACOS: {
'pattern': re.compile(r'^geany-([0-9\.\-]+)_osx(-[0-9]+)?.dmg$'),
'fallback_filename': 'geany-{version}_osx.dmg'
},
}


logger = logging.getLogger(__name__) # pylint: disable=invalid-name


class ReleaseVersions:

source_gzip_version = None
source_bzip2_version = None
windows_version = None
macos_version = None


class ReleaseVersionsProvider:

# ----------------------------------------------------------------------
def __init__(self, releases_directory, fallback_version):
self._releases_directory = releases_directory
self._fallback_version = fallback_version
self._release_files = None
self._release_files_by_version = None
self._release_versions = None

# ----------------------------------------------------------------------
def provide(self):
self._fetch_releases_from_filesystem()
self._group_releases_by_type()
self._factor_release_versions()

return self._release_versions

# ----------------------------------------------------------------------
def _fetch_releases_from_filesystem(self):
self._release_files = list()

if not self._releases_directory:
return

path = Path(self._releases_directory)
for entry in path.iterdir():
relative_entry = entry.relative_to(self._releases_directory)
filename = relative_entry.as_posix()
self._release_files.append(filename)

# ----------------------------------------------------------------------
def _group_releases_by_type(self):
self._release_files_by_version = dict()
for release_type in RELEASE_TYPES:
self._release_files_by_version[release_type] = list()

for filename in self._release_files:
if RELEASE_TYPES[RELEASE_TYPE_SOURCE_GZIP]['pattern'].match(filename):
self._release_files_by_version[RELEASE_TYPE_SOURCE_GZIP].append(filename)

elif RELEASE_TYPES[RELEASE_TYPE_SOURCE_BZIP2]['pattern'].match(filename):
self._release_files_by_version[RELEASE_TYPE_SOURCE_BZIP2].append(filename)

elif RELEASE_TYPES[RELEASE_TYPE_WINDOWS]['pattern'].match(filename):
self._release_files_by_version[RELEASE_TYPE_WINDOWS].append(filename)

elif RELEASE_TYPES[RELEASE_TYPE_MACOS]['pattern'].match(filename):
self._release_files_by_version[RELEASE_TYPE_MACOS].append(filename)

# ----------------------------------------------------------------------
def _factor_release_versions(self):
self._release_versions = ReleaseVersions()
for release_type in self._release_files_by_version:
latest_version = self._determine_latest_version(release_type)

setattr(self._release_versions, release_type, latest_version)

# ----------------------------------------------------------------------
def _determine_latest_version(self, release_type):
versions = self._release_files_by_version[release_type]
sorted_versions = sorted(versions, key=parse_version)
try:
latest_version = sorted_versions.pop()
logger.debug(
'Latest version found for "{}": {}'.format(release_type, latest_version))
except IndexError:
fallback_filename = RELEASE_TYPES[release_type]['fallback_filename']
latest_version = fallback_filename.format(version=self._fallback_version)
logger.debug(
'Latest version found for "{}": {} (fallback)'.format(
release_type,
latest_version))

return latest_version
8 changes: 4 additions & 4 deletions page_content/download/releases.md
Expand Up @@ -3,10 +3,10 @@ Releases

Distribution | File | GPG Signature | GPG Key
----------------- | ------------- | ------------- | -------------
Source (tar.gz) | [geany-{{ geany_latest_version.version }}.tar.gz](https://download.geany.org/geany-{{ geany_latest_version.version }}.tar.gz) | [geany-{{ geany_latest_version.version }}.tar.gz.sig](https://download.geany.org/geany-{{ geany_latest_version.version }}.tar.gz.sig) ([Instructions][4]) | [colombanw-pubkey.txt][1]
Source (tar.bz2) | [geany-{{ geany_latest_version.version }}.tar.bz2](https://download.geany.org/geany-{{ geany_latest_version.version }}.tar.bz2) | [geany-{{ geany_latest_version.version }}.tar.bz2.sig](https://download.geany.org/geany-{{ geany_latest_version.version }}.tar.bz2.sig) ([Instructions][4]) | [colombanw-pubkey.txt][1]
Windows | [geany-{{ geany_latest_version.version }}_setup.exe](https://download.geany.org/geany-{{ geany_latest_version.version }}_setup.exe) | [geany-{{ geany_latest_version.version }}_setup.exe.sig](https://download.geany.org/geany-{{ geany_latest_version.version }}_setup.exe.sig) ([Instructions][4]) | [eht16-pubkey.txt][2]
Mac OSX | [geany-{{ geany_latest_version.version }}_osx.dmg](https://download.geany.org/geany-{{ geany_latest_version.version }}_osx.dmg) | - | -
Source (tar.gz) | [{{ release_versions.source_gzip_version }}](https://download.geany.org/{{ release_versions.source_gzip_version }}) | [{{ release_versions.source_gzip_version }}.sig](https://download.geany.org/{{ release_versions.source_gzip_version }}.sig) ([Instructions][4]) | [colombanw-pubkey.txt][1]
Source (tar.bz2) | [{{ release_versions.source_bzip2_version }}](https://download.geany.org/{{ release_versions.source_bzip2_version }}) | [{{ release_versions.source_bzip2_version }}.sig](https://download.geany.org/{{ release_versions.source_bzip2_version }}.sig) ([Instructions][4]) | [colombanw-pubkey.txt][1]
Windows | [{{ release_versions.windows_version }}](https://download.geany.org/{{ release_versions.windows_version }}) | [{{ release_versions.windows_version }}.sig](https://download.geany.org/{{ release_versions.windows_version }}.sig) ([Instructions][4]) | [eht16-pubkey.txt][2]
Mac OSX | [{{ release_versions.macos_version }}](https://download.geany.org/{{ release_versions.macos_version }}) | - | -

[Release notes for Geany {{ geany_latest_version.version }}][3]

Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Expand Up @@ -8,6 +8,7 @@ django-link-shortener
django-log-request-id
mezzanine-pagedown
mezzanine-sync-pages
packaging
pygments
pylibmc
python-logstash-async
Expand Down

0 comments on commit 23e8033

Please sign in to comment.