Skip to content

Commit

Permalink
Check for sinol-make updates when running (#54)
Browse files Browse the repository at this point in the history
* Add function for checking for sinol-make updates

* Add timeout for update checks

* catch all requests' errors while checking for updates

* Check for updates asynchronously

* Add some comments

* Remove unnecessary print

* Add tests for version checking

* Add more comments

* Fix update comment

Co-authored-by: Tomasz Nowak <[email protected]>

---------

Co-authored-by: Tomasz Nowak <[email protected]>
  • Loading branch information
MasloMaslane and tonowak authored Jul 6, 2023
1 parent c981f1b commit 4a34229
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 1 deletion.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ build
.idea
__pycache__
/tests/packages/**/cache
src/sinol_make/data

# pytest-cov
.coverage
Expand Down
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ dependencies = [
[project.optional-dependencies]
tests = [
"pytest",
"pytest-cov"
"pytest-cov",
"requests-mock",
]

[project.urls]
Expand Down
5 changes: 5 additions & 0 deletions src/sinol_make/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ def main():

for command in commands:
if command.get_name() == args.command:
new_version = util.check_for_updates(__version__)
if new_version is not None:
print(util.warning(f'New version of sinol-make is available (your version: {__version__}, available version: {new_version}).\n'
f' You can update it by running `pip3 install sinol-make --upgrade`.'))

if sys.platform == 'linux' and not util.check_oiejq():
print(util.warning('`oiejq` in `~/.local/bin/` not detected, installing now...'))

Expand Down
71 changes: 71 additions & 0 deletions src/sinol_make/util.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import glob, importlib, os, sys, subprocess, requests, tarfile, yaml
import importlib.resources
import threading


def get_commands():
"""
Expand Down Expand Up @@ -154,6 +157,74 @@ def save_config(config):
yaml.dump(config, config_file)


def check_for_updates(current_version) -> str | None:
"""
Function to check if there is a new version of sinol-make.
:param current_version: current version of sinol-make
:return: returns new version if there is one, None otherwise
"""
data_dir = importlib.resources.files("sinol_make").joinpath("data")
if not data_dir.is_dir():
os.mkdir(data_dir)

# We check for new version asynchronously, so that it doesn't slow down the program.
thread = threading.Thread(target=check_version)
thread.start()
version_file = data_dir.joinpath("version")

if version_file.is_file():
version = version_file.read_text()
try:
if compare_versions(current_version, version) == -1:
return version
else:
return None
except ValueError: # If the version file is corrupted, we just ignore it.
return None
else:
return None


def check_version():
"""
Function that asynchronously checks for new version of sinol-make.
Writes the newest version to data/version file.
"""
try:
request = requests.get("https://pypi.python.org/pypi/sinol-make/json", timeout=1)
except requests.exceptions.RequestException:
return

if request.status_code != 200:
return

data = request.json()
latest_version = data["info"]["version"]

version_file = importlib.resources.files("sinol_make").joinpath("data/version")
version_file.write_text(latest_version)


def compare_versions(version_a, version_b):
"""
Function to compare two versions.
Returns 1 if version_a > version_b, 0 if version_a == version_b, -1 if version_a < version_b.
"""

def convert(version):
return tuple(map(int, version.split(".")))

version_a = convert(version_a)
version_b = convert(version_b)

if version_a > version_b:
return 1
elif version_a == version_b:
return 0
else:
return -1


def lines_diff(lines1, lines2):
"""
Function to compare two lists of lines.
Expand Down
60 changes: 60 additions & 0 deletions tests/test_util.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import os
import sys
import time
import json

import pytest
import importlib.resources

import requests
import requests_mock

from sinol_make import util

Expand All @@ -15,3 +22,56 @@ def test_install_oiejq():
assert not util.check_oiejq()

assert util.install_oiejq()


def test_compare_versions():
"""
Tests for compare_versions function
"""

assert util.compare_versions('1.0.0', '1.0.0') == 0
assert util.compare_versions('1.0.0', '1.0.1') == -1
assert util.compare_versions('1.0.1', '1.0.0') == 1
assert util.compare_versions('1.0.0', '1.1.0') == -1
assert util.compare_versions('1.1.0', '1.0.0') == 1
assert util.compare_versions('1.0.0', '2.0.0') == -1
assert util.compare_versions('2.0.0', '1.0.0') == 1
with pytest.raises(ValueError):
util.compare_versions('1.0.0', '')
with pytest.raises(ValueError):
util.compare_versions('', '1.0.0')
with pytest.raises(ValueError):
util.compare_versions('1.0.0', 'abc')
with pytest.raises(ValueError):
util.compare_versions('abc', '1.0.0')


@requests_mock.Mocker(kw="mocker")
def test_check_version(**kwargs):
"""
Tests for check_version function
Simulates wrong responses and exceptions with requests-mock
"""
mocker = kwargs["mocker"]

data_dir = importlib.resources.files('sinol_make').joinpath("data")
version_file = data_dir.joinpath("version")
if not data_dir.is_dir():
data_dir.mkdir()

# Test correct request
mocker.get("https://pypi.python.org/pypi/sinol-make/json", json={"info": {"version": "1.0.0"}})
util.check_version()
assert version_file.is_file()
assert version_file.read_text() == "1.0.0"
version_file.unlink()

# Test wrong request
mocker.get("https://pypi.python.org/pypi/sinol-make/json", status_code=404)
util.check_version()
assert not version_file.is_file()

# Time out
mocker.get("https://pypi.python.org/pypi/sinol-make/json", exc=requests.exceptions.ConnectTimeout)
util.check_version()
assert not version_file.is_file()

0 comments on commit 4a34229

Please sign in to comment.