[arch-projects] [namcap] [PATCH] Don't report missing-vcs-makedeps when it is in depends

2020-03-17 Thread Felix Yan via arch-projects
Currently a PKGBUILD warning is shown when the package depends on git
instead of makedepends on it. Since we also have the redundant_makedepends
rule we should not write it again in makedepends. This patch checkes depends
array too so this warning could be suppressed.
---
 Namcap/rules/makedepends.py   | 2 ++
 Namcap/tests/pkgbuild/test_makedepends.py | 8 
 2 files changed, 10 insertions(+)

diff --git a/Namcap/rules/makedepends.py b/Namcap/rules/makedepends.py
index 53676c2..8b938a0 100644
--- a/Namcap/rules/makedepends.py
+++ b/Namcap/rules/makedepends.py
@@ -68,6 +68,8 @@ class VCSMakedepends(PkgbuildRule):
 
for v in protocols:
d = vcs[v]
+   if 'depends' in pkginfo and d in pkginfo["depends"]:
+   continue
if 'makedepends' not in pkginfo:
missing.append(d)
continue
diff --git a/Namcap/tests/pkgbuild/test_makedepends.py 
b/Namcap/tests/pkgbuild/test_makedepends.py
index d443b2b..73a3ba2 100644
--- a/Namcap/tests/pkgbuild/test_makedepends.py
+++ b/Namcap/tests/pkgbuild/test_makedepends.py
@@ -111,4 +111,12 @@ package() {
self.assertEqual(r.warnings, [])
self.assertEqual(r.infos, [])
 
+   def test_example3(self):
+   # Example 3
+   r = self.run_on_pkg(self.pkgbuild1 + 'depends=(bzr git 
mercurial)')
+   self.assertEqual(r.errors, [])
+   self.assertEqual(r.warnings,
+   [("missing-vcs-makedeps %s", 'subversion')])
+   self.assertEqual(r.infos, [])
+
 # vim: set ts=4 sw=4 noet:
-- 
2.25.1


[arch-projects] [namcap] [PATCH] Add: rule to detect Python dependencies

2020-01-07 Thread Felix Yan via arch-projects
---
 Namcap/rules/__init__.py   |   1 +
 Namcap/rules/pydepends.py  | 122 +
 Namcap/tests/package/test_pydepends.py |  68 ++
 3 files changed, 191 insertions(+)
 create mode 100644 Namcap/rules/pydepends.py
 create mode 100644 Namcap/tests/package/test_pydepends.py

diff --git a/Namcap/rules/__init__.py b/Namcap/rules/__init__.py
index 525dbc6..01d1b96 100644
--- a/Namcap/rules/__init__.py
+++ b/Namcap/rules/__init__.py
@@ -43,6 +43,7 @@ from . import (
   perllocal,
   permissions,
   py_mtime,
+  pydepends,
   rpath,
   scrollkeeper,
   shebangdepends,
diff --git a/Namcap/rules/pydepends.py b/Namcap/rules/pydepends.py
new file mode 100644
index 000..efc6735
--- /dev/null
+++ b/Namcap/rules/pydepends.py
@@ -0,0 +1,122 @@
+# -*- coding: utf-8 -*-
+#
+# namcap rules - pydepends
+# Copyright (C) 2020 Felix Yan 
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 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 General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#
+
+from collections import defaultdict
+import ast
+import sys
+import sysconfig
+import Namcap.package
+from Namcap.ruleclass import *
+
+
+def finddepends(liblist):
+   """
+   Find packages owning a list of libraries
+
+   Returns:
+ dependlist -- a dictionary { package => set(libraries) }
+ orphans -- the list of libraries without owners
+   """
+   dependlist = defaultdict(set)
+
+   pymatches = {}
+
+   knownlibs = set(liblist)
+   foundlibs = set()
+
+   workarounds = {
+   "python": sys.builtin_module_names
+   }
+
+   for pkg in Namcap.package.get_installed_packages():
+   for j, fsize, fmode in pkg.files:
+   if not j.startswith("usr/lib/python3"):
+   continue
+
+   for k in knownlibs:
+   if j.endswith("site-packages/" + k + "/") or 
j.endswith("site-packages/" + k + ".py") or \
+   j.endswith("site-packages/" + k 
+ ".so") or \
+   j.endswith("site-packages/" + k 
+ sysconfig.get_config_var('EXT_SUFFIX')) or \
+   j.endswith("lib-dynload/" + k + 
sysconfig.get_config_var('EXT_SUFFIX')) or \
+   j.count("/") == 3 and 
j.endswith("/" + k + ".py") or \
+   j.count("/") == 4 and 
j.endswith("/" + k + "/") or \
+   pkg.name in workarounds and k 
in workarounds[pkg.name]:
+   dependlist[pkg.name].add(k)
+   foundlibs.add(k)
+
+   orphans = list(knownlibs - foundlibs)
+   return dependlist, orphans
+
+
+def get_imports(file):
+   root = ast.parse(file.read())
+
+   for node in ast.walk(root):
+   if isinstance(node, ast.Import):
+   for module in node.names:
+   yield module.name.split('.')[0]
+   elif isinstance(node, ast.ImportFrom):
+   if node.module and node.level == 0:
+   yield node.module.split('.')[0]
+
+
+class PythonDependencyRule(TarballRule):
+   name = "pydepends"
+   description = "Checks python dependencies"
+   def analyze(self, pkginfo, tar):
+   liblist = defaultdict(set)
+   own_liblist = set()
+
+   for entry in tar:
+   if not entry.isfile() or not entry.name.endswith('.py'):
+   continue
+   own_liblist.add(entry.name[:-3])
+   f = tar.extractfile(entry)
+   for module in get_imports(f):
+   liblist[module].add(entry.name)
+   f.close()
+
+   for lib in own_liblist:
+   liblist.pop(lib, None)
+
+   dependlist, orphans = finddepends(liblist)
+
+   # Handle "no package associated" errors
+   self.warnings.extend([("library-no-package-associated %s", i)
+   for i in orphans])
+
+   # Print link-level deps
+   for pkg, libraries in