mirror of
https://github.com/YunoHost/package_linter.git
synced 2024-09-03 20:06:12 +02:00
Fixed (most) linter complaints.
This commit is contained in:
parent
c6cbd26235
commit
3dcd83eb78
3 changed files with 46 additions and 50 deletions
|
@ -12,6 +12,7 @@ import six
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class RawNginxParser(object):
|
class RawNginxParser(object):
|
||||||
# pylint: disable=expression-not-assigned
|
# pylint: disable=expression-not-assigned
|
||||||
# pylint: disable=pointless-statement
|
# pylint: disable=pointless-statement
|
||||||
|
@ -63,6 +64,7 @@ class RawNginxParser(object):
|
||||||
"""Returns the parsed tree as a list."""
|
"""Returns the parsed tree as a list."""
|
||||||
return self.parse().asList()
|
return self.parse().asList()
|
||||||
|
|
||||||
|
|
||||||
class RawNginxDumper(object):
|
class RawNginxDumper(object):
|
||||||
# pylint: disable=too-few-public-methods
|
# pylint: disable=too-few-public-methods
|
||||||
"""A class that dumps nginx configuration from the provided tree."""
|
"""A class that dumps nginx configuration from the provided tree."""
|
||||||
|
@ -147,7 +149,8 @@ def dump(blocks, _file):
|
||||||
return _file.write(dumps(blocks))
|
return _file.write(dumps(blocks))
|
||||||
|
|
||||||
|
|
||||||
spacey = lambda x: (isinstance(x, six.string_types) and x.isspace()) or x == ''
|
def spacey(x): return (isinstance(x, six.string_types) and x.isspace()) or x == ''
|
||||||
|
|
||||||
|
|
||||||
class UnspacedList(list):
|
class UnspacedList(list):
|
||||||
"""Wrap a list [of lists], making any whitespace entries magically invisible"""
|
"""Wrap a list [of lists], making any whitespace entries magically invisible"""
|
||||||
|
@ -186,7 +189,6 @@ class UnspacedList(list):
|
||||||
inbound = UnspacedList(inbound)
|
inbound = UnspacedList(inbound)
|
||||||
return (inbound, inbound.spaced)
|
return (inbound, inbound.spaced)
|
||||||
|
|
||||||
|
|
||||||
def insert(self, i, x):
|
def insert(self, i, x):
|
||||||
item, spaced_item = self._coerce(x)
|
item, spaced_item = self._coerce(x)
|
||||||
slicepos = self._spaced_position(i) if i < len(self) else len(self.spaced)
|
slicepos = self._spaced_position(i) if i < len(self) else len(self.spaced)
|
||||||
|
@ -209,19 +211,23 @@ class UnspacedList(list):
|
||||||
self.dirty = True
|
self.dirty = True
|
||||||
|
|
||||||
def __add__(self, other):
|
def __add__(self, other):
|
||||||
l = copy.deepcopy(self)
|
zzz = copy.deepcopy(self)
|
||||||
l.extend(other)
|
zzz.extend(other)
|
||||||
l.dirty = True
|
zzz.dirty = True
|
||||||
return l
|
return zzz
|
||||||
|
|
||||||
def pop(self, _i=None):
|
def pop(self, _i=None):
|
||||||
raise NotImplementedError("UnspacedList.pop() not yet implemented")
|
raise NotImplementedError("UnspacedList.pop() not yet implemented")
|
||||||
|
|
||||||
def remove(self, _):
|
def remove(self, _):
|
||||||
raise NotImplementedError("UnspacedList.remove() not yet implemented")
|
raise NotImplementedError("UnspacedList.remove() not yet implemented")
|
||||||
|
|
||||||
def reverse(self):
|
def reverse(self):
|
||||||
raise NotImplementedError("UnspacedList.reverse() not yet implemented")
|
raise NotImplementedError("UnspacedList.reverse() not yet implemented")
|
||||||
|
|
||||||
def sort(self, _cmp=None, _key=None, _Rev=None):
|
def sort(self, _cmp=None, _key=None, _Rev=None):
|
||||||
raise NotImplementedError("UnspacedList.sort() not yet implemented")
|
raise NotImplementedError("UnspacedList.sort() not yet implemented")
|
||||||
|
|
||||||
def __setslice__(self, _i, _j, _newslice):
|
def __setslice__(self, _i, _j, _newslice):
|
||||||
raise NotImplementedError("Slice operations on UnspacedLists not yet implemented")
|
raise NotImplementedError("Slice operations on UnspacedLists not yet implemented")
|
||||||
|
|
||||||
|
@ -241,9 +247,9 @@ class UnspacedList(list):
|
||||||
|
|
||||||
def __deepcopy__(self, memo):
|
def __deepcopy__(self, memo):
|
||||||
new_spaced = copy.deepcopy(self.spaced, memo=memo)
|
new_spaced = copy.deepcopy(self.spaced, memo=memo)
|
||||||
l = UnspacedList(new_spaced)
|
zzz = UnspacedList(new_spaced)
|
||||||
l.dirty = self.dirty
|
zzz.dirty = self.dirty
|
||||||
return l
|
return zzz
|
||||||
|
|
||||||
def is_dirty(self):
|
def is_dirty(self):
|
||||||
"""Recurse through the parse tree to figure out if any sublists are dirty"""
|
"""Recurse through the parse tree to figure out if any sublists are dirty"""
|
||||||
|
|
|
@ -15,13 +15,13 @@ from datetime import datetime
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import toml
|
import toml
|
||||||
except:
|
except Exception:
|
||||||
os.system('pip3 install toml')
|
os.system('pip3 install toml')
|
||||||
import toml
|
import toml
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import jsonschema
|
import jsonschema
|
||||||
except:
|
except Exception:
|
||||||
os.system('pip3 install jsonschema')
|
os.system('pip3 install jsonschema')
|
||||||
import jsonschema
|
import jsonschema
|
||||||
|
|
||||||
|
@ -393,6 +393,7 @@ class TestSuite:
|
||||||
test_name = test.__qualname__
|
test_name = test.__qualname__
|
||||||
tests_reports[report_type(report)].append((test_name, report))
|
tests_reports[report_type(report)].append((test_name, report))
|
||||||
|
|
||||||
|
|
||||||
# Defined in packaging module
|
# Defined in packaging module
|
||||||
# See https://github.com/pypa/packaging/blob/20cd09e00917adbc4afeaa753be831a6bc2740f7/packaging/version.py#L225
|
# See https://github.com/pypa/packaging/blob/20cd09e00917adbc4afeaa753be831a6bc2740f7/packaging/version.py#L225
|
||||||
VERSION_PATTERN = r"""
|
VERSION_PATTERN = r"""
|
||||||
|
@ -628,7 +629,6 @@ class App(TestSuite):
|
||||||
-> note that in these files, the __FOOBAR__ syntax is supported and replaced with the corresponding 'foobar' setting.
|
-> note that in these files, the __FOOBAR__ syntax is supported and replaced with the corresponding 'foobar' setting.
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
@test()
|
@test()
|
||||||
def disclaimer_wording_or_placeholder(app):
|
def disclaimer_wording_or_placeholder(app):
|
||||||
if os.path.exists(app.path + "/doc"):
|
if os.path.exists(app.path + "/doc"):
|
||||||
|
@ -653,7 +653,6 @@ class App(TestSuite):
|
||||||
"The doc/ folder seems to still contain some dummy, placeholder messages in the .md markdown files. If those files are not useful in the context of your app, simply remove them."
|
"The doc/ folder seems to still contain some dummy, placeholder messages in the .md markdown files. If those files are not useful in the context of your app, simply remove them."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@test()
|
@test()
|
||||||
def change_url_script(app):
|
def change_url_script(app):
|
||||||
|
|
||||||
|
@ -700,7 +699,7 @@ class App(TestSuite):
|
||||||
|
|
||||||
content = open(app.path + "/README.md").read()
|
content = open(app.path + "/README.md").read()
|
||||||
|
|
||||||
if not "This README was automatically generated" in content or not "dash.yunohost.org/integration/%s.svg" % id_ in content:
|
if "This README was automatically generated" not in content or not "dash.yunohost.org/integration/%s.svg" % id_ in content:
|
||||||
yield Warning(
|
yield Warning(
|
||||||
"It looks like the README was not generated automatically by https://github.com/YunoHost/apps/tree/master/tools/README-generator. "
|
"It looks like the README was not generated automatically by https://github.com/YunoHost/apps/tree/master/tools/README-generator. "
|
||||||
"Note that nowadays you are not suppose to edit README.md, the yunohost bot will usually automatically update it if your app is hosted in the YunoHost-Apps org ... or you can also generate it by running the README-generator yourself."
|
"Note that nowadays you are not suppose to edit README.md, the yunohost bot will usually automatically update it if your app is hosted in the YunoHost-Apps org ... or you can also generate it by running the README-generator yourself."
|
||||||
|
@ -726,7 +725,7 @@ class App(TestSuite):
|
||||||
|
|
||||||
if (
|
if (
|
||||||
os.system(
|
os.system(
|
||||||
"grep -q 'Explain in *a few (10~15) words* the purpose of the app\|Expliquez en *quelques* (10~15) mots' %s/manifest.json 2>/dev/null" % self.path
|
"grep -q 'Explain in *a few (10~15) words* the purpose of the app\\|Expliquez en *quelques* (10~15) mots' %s/manifest.json 2>/dev/null" % self.path
|
||||||
)
|
)
|
||||||
== 0
|
== 0
|
||||||
):
|
):
|
||||||
|
@ -743,7 +742,7 @@ class App(TestSuite):
|
||||||
def bad_encoding(self):
|
def bad_encoding(self):
|
||||||
|
|
||||||
cmd = (
|
cmd = (
|
||||||
"file --mime-encoding $(find %s/ -type f) | grep 'iso-8859-1\|unknown-8bit' || true"
|
"file --mime-encoding $(find %s/ -type f) | grep 'iso-8859-1\\|unknown-8bit' || true"
|
||||||
% self.path
|
% self.path
|
||||||
)
|
)
|
||||||
bad_encoding_files = (
|
bad_encoding_files = (
|
||||||
|
@ -772,7 +771,7 @@ class App(TestSuite):
|
||||||
@test()
|
@test()
|
||||||
def helpers_now_official(app):
|
def helpers_now_official(app):
|
||||||
|
|
||||||
cmd = "grep -IhEro 'ynh_\w+ *\( *\)' '%s/scripts' | tr -d '() '" % app.path
|
cmd = "grep -IhEro 'ynh_\\w+ *\\( *\\)' '%s/scripts' | tr -d '() '" % app.path
|
||||||
custom_helpers = (
|
custom_helpers = (
|
||||||
subprocess.check_output(cmd, shell=True).decode("utf-8").strip().split("\n")
|
subprocess.check_output(cmd, shell=True).decode("utf-8").strip().split("\n")
|
||||||
)
|
)
|
||||||
|
@ -788,7 +787,7 @@ class App(TestSuite):
|
||||||
@test()
|
@test()
|
||||||
def helpers_version_requirement(app):
|
def helpers_version_requirement(app):
|
||||||
|
|
||||||
cmd = "grep -IhEro 'ynh_\w+ *\( *\)' '%s/scripts' | tr -d '() '" % app.path
|
cmd = "grep -IhEro 'ynh_\\w+ *\\( *\\)' '%s/scripts' | tr -d '() '" % app.path
|
||||||
custom_helpers = (
|
custom_helpers = (
|
||||||
subprocess.check_output(cmd, shell=True).decode("utf-8").strip().split("\n")
|
subprocess.check_output(cmd, shell=True).decode("utf-8").strip().split("\n")
|
||||||
)
|
)
|
||||||
|
@ -803,7 +802,7 @@ class App(TestSuite):
|
||||||
app.manifest.get("integration", {}).get("yunohost", "").strip(">= ")
|
app.manifest.get("integration", {}).get("yunohost", "").strip(">= ")
|
||||||
)
|
)
|
||||||
|
|
||||||
cmd = "grep -IhEro 'ynh_\w+' '%s/scripts'" % app.path
|
cmd = "grep -IhEro 'ynh_\\w+' '%s/scripts'" % app.path
|
||||||
helpers_used = (
|
helpers_used = (
|
||||||
subprocess.check_output(cmd, shell=True).decode("utf-8").strip().split("\n")
|
subprocess.check_output(cmd, shell=True).decode("utf-8").strip().split("\n")
|
||||||
)
|
)
|
||||||
|
@ -839,7 +838,7 @@ class App(TestSuite):
|
||||||
if app_packaging_format <= 1:
|
if app_packaging_format <= 1:
|
||||||
return
|
return
|
||||||
|
|
||||||
cmd = f"grep -IhEro 'ynh_\w+' '{app.path}/scripts/install' '{app.path}/scripts/remove' '{app.path}/scripts/upgrade' '{app.path}/scripts/backup' '{app.path}/scripts/restore' || true"
|
cmd = f"grep -IhEro 'ynh_\\w+' '{app.path}/scripts/install' '{app.path}/scripts/remove' '{app.path}/scripts/upgrade' '{app.path}/scripts/backup' '{app.path}/scripts/restore' || true"
|
||||||
helpers_used = (
|
helpers_used = (
|
||||||
subprocess.check_output(cmd, shell=True).decode("utf-8").strip().split("\n")
|
subprocess.check_output(cmd, shell=True).decode("utf-8").strip().split("\n")
|
||||||
)
|
)
|
||||||
|
@ -978,14 +977,12 @@ class App(TestSuite):
|
||||||
):
|
):
|
||||||
yield Error("Don't do black magic with /etc/ssowat/conf.json.persistent!")
|
yield Error("Don't do black magic with /etc/ssowat/conf.json.persistent!")
|
||||||
|
|
||||||
|
|
||||||
@test()
|
@test()
|
||||||
def bad_final_path_location(self):
|
def bad_final_path_location(self):
|
||||||
if os.system(f"grep -q -nr 'ynh_webpath_register' {self.path}/scripts/install 2>/dev/null") == 0 \
|
if os.system(f"grep -q -nr 'ynh_webpath_register' {self.path}/scripts/install 2>/dev/null") == 0 \
|
||||||
and os.system(f"grep -q -nr 'final_path=/opt' {self.path}/scripts/install {self.path}/scripts/_common.sh 2>/dev/null") == 0:
|
and os.system(f"grep -q -nr 'final_path=/opt' {self.path}/scripts/install {self.path}/scripts/_common.sh 2>/dev/null") == 0:
|
||||||
yield Info("Web applications are not supposed to be installed in /opt/ ... They are supposed to be installed in /var/www/$app :/")
|
yield Info("Web applications are not supposed to be installed in /opt/ ... They are supposed to be installed in /var/www/$app :/")
|
||||||
|
|
||||||
|
|
||||||
@test()
|
@test()
|
||||||
def app_data_in_unofficial_dir(self):
|
def app_data_in_unofficial_dir(self):
|
||||||
|
|
||||||
|
@ -1039,7 +1036,6 @@ class Configurations(TestSuite):
|
||||||
|
|
||||||
app = self.app
|
app = self.app
|
||||||
|
|
||||||
|
|
||||||
if app_packaging_format <= 1:
|
if app_packaging_format <= 1:
|
||||||
check_process_file = app.path + "/check_process"
|
check_process_file = app.path + "/check_process"
|
||||||
if not file_exists(check_process_file):
|
if not file_exists(check_process_file):
|
||||||
|
@ -1064,7 +1060,7 @@ class Configurations(TestSuite):
|
||||||
|
|
||||||
if os.system("grep -q 'Level 5=1' '%s'" % check_process_file) == 0:
|
if os.system("grep -q 'Level 5=1' '%s'" % check_process_file) == 0:
|
||||||
yield Error("Do not force Level 5=1 in check_process...")
|
yield Error("Do not force Level 5=1 in check_process...")
|
||||||
elif os.system("grep -qE ' *Level \d=' '%s'" % check_process_file) == 0:
|
elif os.system("grep -qE ' *Level \\d=' '%s'" % check_process_file) == 0:
|
||||||
yield Warning(
|
yield Warning(
|
||||||
"Setting Level x=y in check_process is obsolete / not relevant anymore"
|
"Setting Level x=y in check_process is obsolete / not relevant anymore"
|
||||||
)
|
)
|
||||||
|
@ -1118,7 +1114,7 @@ class Configurations(TestSuite):
|
||||||
"It looks like you forgot to enable setup_sub_dir test in check_process?"
|
"It looks like you forgot to enable setup_sub_dir test in check_process?"
|
||||||
)
|
)
|
||||||
|
|
||||||
if app.manifest.get("multi_instance") in [True, 1, "True", "true"] or app.manifest.get("integration", {}).get("multi_instance") == True:
|
if app.manifest.get("multi_instance") in [True, 1, "True", "true"] or app.manifest.get("integration", {}).get("multi_instance") is True:
|
||||||
if (
|
if (
|
||||||
os.system(r"grep -q '^\s*multi_instance=1' '%s'" % check_process_file)
|
os.system(r"grep -q '^\s*multi_instance=1' '%s'" % check_process_file)
|
||||||
!= 0
|
!= 0
|
||||||
|
@ -1396,7 +1392,7 @@ class Configurations(TestSuite):
|
||||||
if "location" in content and "more_set_headers" in content:
|
if "location" in content and "more_set_headers" in content:
|
||||||
|
|
||||||
lines = content.split("\n")
|
lines = content.split("\n")
|
||||||
more_set_headers_lines = [l for l in lines if "more_set_headers" in l]
|
more_set_headers_lines = [zzz for zzz in lines if "more_set_headers" in zzz]
|
||||||
|
|
||||||
def right_syntax(line):
|
def right_syntax(line):
|
||||||
return re.search(
|
return re.search(
|
||||||
|
@ -1425,7 +1421,6 @@ class Configurations(TestSuite):
|
||||||
or "nginx" not in filename
|
or "nginx" not in filename
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
content = open(app.path + "/conf/" + filename).read()
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Path traversal issues
|
# Path traversal issues
|
||||||
|
@ -1483,7 +1478,7 @@ class Configurations(TestSuite):
|
||||||
import pyparsing, six
|
import pyparsing, six
|
||||||
|
|
||||||
do_path_traversal_check = True
|
do_path_traversal_check = True
|
||||||
except:
|
except Exception:
|
||||||
# If inside a venv, try to magically install pyparsing
|
# If inside a venv, try to magically install pyparsing
|
||||||
if "VIRTUAL_ENV" in os.environ:
|
if "VIRTUAL_ENV" in os.environ:
|
||||||
try:
|
try:
|
||||||
|
@ -1738,7 +1733,6 @@ class Manifest(TestSuite):
|
||||||
if not self.manifest.get("upstream", {}).get("license"):
|
if not self.manifest.get("upstream", {}).get("license"):
|
||||||
yield Error("Missing 'license' key in the upstream section")
|
yield Error("Missing 'license' key in the upstream section")
|
||||||
|
|
||||||
|
|
||||||
@test()
|
@test()
|
||||||
def license(self):
|
def license(self):
|
||||||
|
|
||||||
|
@ -1774,7 +1768,6 @@ class Manifest(TestSuite):
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
@test()
|
@test()
|
||||||
def description(self):
|
def description(self):
|
||||||
|
|
||||||
|
@ -1988,7 +1981,6 @@ class Manifest(TestSuite):
|
||||||
"You should add a 'init_main_permission' question, or define `allowed` for main permission to have the app ready to be accessed right after installation."
|
"You should add a 'init_main_permission' question, or define `allowed` for main permission to have the app ready to be accessed right after installation."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@test()
|
@test()
|
||||||
def manifest_schema(self):
|
def manifest_schema(self):
|
||||||
|
|
||||||
|
@ -2099,10 +2091,6 @@ class AppCatalog(TestSuite):
|
||||||
if self.catalog_infos:
|
if self.catalog_infos:
|
||||||
repo_url = self.catalog_infos["url"]
|
repo_url = self.catalog_infos["url"]
|
||||||
|
|
||||||
all_urls = [
|
|
||||||
infos.get("url", "").lower() for infos in self.app_list.values()
|
|
||||||
]
|
|
||||||
|
|
||||||
if repo_url.lower() not in [repo_org.lower(), repo_brique.lower()]:
|
if repo_url.lower() not in [repo_org.lower(), repo_brique.lower()]:
|
||||||
if repo_url.lower().startswith("https://github.com/YunoHost-Apps/"):
|
if repo_url.lower().startswith("https://github.com/YunoHost-Apps/"):
|
||||||
yield Warning(
|
yield Warning(
|
||||||
|
@ -2433,11 +2421,10 @@ class Script(TestSuite):
|
||||||
if os.system(cmd) == 0:
|
if os.system(cmd) == 0:
|
||||||
yield Warning("It looks like this app requires the admin to finish the install by entering DB credentials. Unless it's absolutely not easily automatizable, this should be handled automatically by the app install script using curl calls, or (CLI tools provided by the upstream maybe ?).")
|
yield Warning("It looks like this app requires the admin to finish the install by entering DB credentials. Unless it's absolutely not easily automatizable, this should be handled automatically by the app install script using curl calls, or (CLI tools provided by the upstream maybe ?).")
|
||||||
|
|
||||||
|
|
||||||
@test(only=["install", "upgrade"])
|
@test(only=["install", "upgrade"])
|
||||||
def deprecated_replace_string(self):
|
def deprecated_replace_string(self):
|
||||||
cmd1 = "grep -Ec 'ynh_replace_string' '%s' || true" % self.path
|
cmd1 = "grep -Ec 'ynh_replace_string' '%s' || true" % self.path
|
||||||
cmd2 = "grep -Ec 'ynh_replace_string.*__\w+__' '%s' || true" % self.path
|
cmd2 = "grep -Ec 'ynh_replace_string.*__\\w+__' '%s' || true" % self.path
|
||||||
|
|
||||||
count1 = int(subprocess.check_output(cmd1, shell=True).decode("utf-8").strip())
|
count1 = int(subprocess.check_output(cmd1, shell=True).decode("utf-8").strip())
|
||||||
count2 = int(subprocess.check_output(cmd2, shell=True).decode("utf-8").strip())
|
count2 = int(subprocess.check_output(cmd2, shell=True).decode("utf-8").strip())
|
||||||
|
@ -2729,7 +2716,7 @@ class Script(TestSuite):
|
||||||
if match:
|
if match:
|
||||||
try:
|
try:
|
||||||
return int(match.groups()[0])
|
return int(match.groups()[0])
|
||||||
except:
|
except Exception:
|
||||||
return -1
|
return -1
|
||||||
else:
|
else:
|
||||||
return 1
|
return 1
|
||||||
|
|
3
tox.ini
Normal file
3
tox.ini
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[flake8]
|
||||||
|
extend-ignore = E501
|
||||||
|
exclude = .git,__pycache__
|
Loading…
Reference in a new issue