Skip to content

Commit 9723617

Browse files
authored
Merge pull request #75 from gnikit/feature/fetch-updates
Added fortls autoupdate during initialisation
2 parents 65bfb20 + 40fa549 commit 9723617

File tree

7 files changed

+98
-4
lines changed

7 files changed

+98
-4
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# CHANGELONG
22

3+
## 2.2.6
4+
5+
### Added
6+
7+
- Added the capability for `fortls` to auto-update use `--disable_autoupdate` to disable
8+
([#76](https://github.com/gnikit/fortls/issues/76))
9+
310
## 2.2.5
411

512
### Changed

fortls/interface.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ def commandline_args(name: str = "fortls") -> argparse.ArgumentParser:
7676
" as is)"
7777
),
7878
)
79+
parser.add_argument(
80+
"--disable_autoupdate",
81+
action="store_true",
82+
help=(
83+
"fortls automatically checks PyPi for newer version and installs them."
84+
"Use this option to disable the autoupdate feature."
85+
),
86+
)
7987
# XXX: Deprecated, argument not attached to anything. Remove
8088
parser.add_argument(
8189
"--preserve_keyword_order",

fortls/langserver.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,16 @@
55
import logging
66
import os
77
import re
8+
import subprocess
9+
import sys
810
import traceback
11+
import urllib.request
912
from multiprocessing import Pool
1013
from pathlib import Path
1114
from typing import Pattern
15+
from urllib.error import URLError
16+
17+
from packaging import version
1218

1319
# Local modules
1420
from fortls.constants import (
@@ -208,6 +214,8 @@ def serve_initialize(self, request):
208214
self._config_logger(request)
209215
self._load_intrinsics()
210216
self._add_source_dirs()
217+
if self._update_version_pypi():
218+
log.log("Please restart the server for new version to activate")
211219

212220
# Initialize workspace
213221
self.workspace_init()
@@ -1486,6 +1494,9 @@ def _load_config_file_general(self, config_dict: dict) -> None:
14861494
)
14871495
self.sync_type: int = 2 if self.incremental_sync else 1
14881496
self.sort_keywords = config_dict.get("sort_keywords", self.sort_keywords)
1497+
self.disable_autoupdate = config_dict.get(
1498+
"disable_autoupdate", self.disable_autoupdate
1499+
)
14891500

14901501
# Autocomplete options -------------------------------------------------
14911502
self.autocomplete_no_prefix = config_dict.get(
@@ -1634,6 +1645,55 @@ def _create_ref_link(self, obj):
16341645
},
16351646
}
16361647

1648+
def _update_version_pypi(self, test: bool = False):
1649+
"""Fetch updates from PyPi for fortls
1650+
1651+
Parameters
1652+
----------
1653+
test : bool, optional
1654+
flag used to override exit checks, only for unittesting, by default False
1655+
"""
1656+
if self.disable_autoupdate:
1657+
return False
1658+
v = version.parse(__version__)
1659+
# Do not run for prerelease and dev release
1660+
if v.is_prerelease and not test:
1661+
return False
1662+
try:
1663+
# For security reasons register as Request before opening
1664+
request = urllib.request.Request("https://pypi.org/pypi/fortls/json")
1665+
with urllib.request.urlopen(request) as resp:
1666+
info = json.loads(resp.read().decode("utf-8"))
1667+
# This is the only reliable way to compare version semantics
1668+
if version.parse(info["info"]["version"]) > v or test:
1669+
self.post_message(
1670+
f"Using fortls {__version__}. A newer version of is"
1671+
" available through PyPi. An attempt will be made to update"
1672+
" the server",
1673+
3,
1674+
)
1675+
# Run pip
1676+
result = subprocess.run(
1677+
[
1678+
sys.executable,
1679+
"-m",
1680+
"pip",
1681+
"install",
1682+
"fortls",
1683+
"--upgrade",
1684+
],
1685+
capture_output=True,
1686+
)
1687+
if result.stdout:
1688+
log.info(result.stdout)
1689+
if result.stderr:
1690+
log.error(result.stderr)
1691+
return True
1692+
# No internet connection exceptions
1693+
except (URLError, KeyError):
1694+
log.warning("Failed to update the fortls Language Server")
1695+
return False
1696+
16371697

16381698
class JSONRPC2Error(Exception):
16391699
def __init__(self, code, message, data=None):

fortls/objects.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
VAR_TYPE_ID,
2626
WHERE_TYPE_ID,
2727
FRegex,
28-
USE_info,
2928
INCLUDE_info,
29+
USE_info,
3030
)
3131
from fortls.helper_functions import get_keywords, get_paren_substring, get_var_stack
3232
from fortls.jsonrpc import path_to_uri

fortls/parse_fortran.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
PY3K,
1919
SELECT_TYPE_ID,
2020
SUBMODULE_TYPE_ID,
21+
CLASS_info,
2122
FRegex,
2223
FUN_sig,
23-
RESULT_sig,
24-
CLASS_info,
2524
GEN_info,
2625
INT_info,
26+
RESULT_sig,
2727
SELECT_info,
2828
SMOD_info,
2929
SUB_info,

test/test_interface.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@
1212
def test_command_line_general_options():
1313
args = parser.parse_args(
1414
"-c config_file.json -n 2 --notify_init --incremental_sync --sort_keywords"
15-
" --debug_log".split()
15+
" --disable_autoupdate --debug_log".split()
1616
)
1717
assert args.config == "config_file.json"
1818
assert args.nthreads == 2
1919
assert args.notify_init
2020
assert args.incremental_sync
2121
assert args.sort_keywords
22+
assert args.disable_autoupdate
2223
assert args.debug_log
2324

2425

@@ -103,6 +104,7 @@ def test_config_file_general_options():
103104
assert server.notify_init
104105
assert server.incremental_sync
105106
assert server.sort_keywords
107+
assert server.disable_autoupdate
106108

107109

108110
def test_config_file_dir_parsing_options():
@@ -164,3 +166,19 @@ def test_config_file_codeactions_options():
164166
server, root = unittest_server_init()
165167
# Code Actions options
166168
assert server.enable_code_actions
169+
170+
171+
def test_version_update_pypi():
172+
from fortls.langserver import LangServer
173+
from fortls.jsonrpc import JSONRPC2Connection, ReadWriter
174+
175+
parser = commandline_args("fortls")
176+
args = parser.parse_args("-c f90_config.json".split())
177+
args = vars(args)
178+
args["disable_autoupdate"] = False
179+
180+
stdin, stdout = sys.stdin.buffer, sys.stdout.buffer
181+
s = LangServer(conn=JSONRPC2Connection(ReadWriter(stdin, stdout)), settings=args)
182+
s.root_path = (Path(__file__).parent / "test_source").resolve()
183+
did_update = s._update_version_pypi(test=True)
184+
assert did_update

test/test_source/f90_config.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"notify_init": true,
44
"incremental_sync": true,
55
"sort_keywords": true,
6+
"disable_autoupdate": true,
67

78
"source_dirs": ["subdir", "pp/**"],
89
"incl_suffixes": [".FF", ".fpc", ".h", "f20"],

0 commit comments

Comments
 (0)