summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2019-04-06 22:56:53 -0400
committerLuke Shumaker <lukeshu@lukeshu.com>2019-04-07 00:00:23 -0400
commit057767ca8df1b7c84f86413e3d2aa208fddbb5ec (patch)
tree459f6d30083481b2f2d88ac6e573ed9a5c5422a7
parentd624faea3d62a5dab5dce6d7a14b6c27f8fddea9 (diff)
list-depends: Get much more robust with parsing requirements.txt
-rwxr-xr-xlist-depends28
-rwxr-xr-xpip2pacman78
2 files changed, 80 insertions, 26 deletions
diff --git a/list-depends b/list-depends
index ddcef9e..f248ccb 100755
--- a/list-depends
+++ b/list-depends
@@ -18,29 +18,5 @@
[[ -n $stat_file ]] || stat_file='depends_static.txt'
[[ -n $prod_file ]] || prod_file='https://projects.parabolagnulinux.org/parabolaweb.git/plain/requirements_prod.txt'
-cat "${stat_file}" |
-sed -r \
- -e 's/\s*#.*//'
-
-curl -s "${prod_file}" |
-sed -r \
- -e 's|^-e .*/fredj/cssmin.git@master#egg=cssmin$|python2-cssmin-fredj|' \
- -e 's/.*/\L&/' \
- -e 's/^(python2?-)?/python2-/' |
-while read -r dep; do
- # This one is a little more complicated, because with ==
- # depends, I don't want to actually lock to that precise of a
- # version; it would be a nightmare with keeping things in
- # sync. So, let's turn == into >=, but also make sure the
- # first two segments match.
- if [[ $dep = *==* ]]; then
- name="${dep%%==*}"
- ver="${dep#*==}"
- IFS=.
- read major minor patch <<<"$ver"
- echo "$name>=$ver"
- echo "$name<$major.$((minor+1))"
- else
- echo "$dep"
- fi
-done
+sed -r -e 's/\s*#.*//' <"${stat_file}"
+"$(dirname -- "$0")/pip2pacman" "${prod_file}"
diff --git a/pip2pacman b/pip2pacman
new file mode 100755
index 0000000..ff1975b
--- /dev/null
+++ b/pip2pacman
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2013, 2015, 2019 Luke Shumaker <lukeshu@parabola.nu>
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+import re
+
+from pip._internal.req import parse_requirements
+from pip._internal.download import PipSession
+from packaging.specifiers import Specifier
+
+vcspkgs = {
+ 'git+git://github.com/fredj/cssmin.git@master#egg=cssmin': 'python2-cssmin-fredj',
+}
+
+
+def nextver(ver):
+ parts = re.sub(r"(a|b|rc|\.dev|\.post|\+).*", '', ver).split('.')
+ parts.pop()
+ parts += [str(int(parts.pop())+1)]
+ return '.'.join(parts)
+
+
+# https://pip.pypa.io/en/stable/reference/pip_install/#requirements-file-format
+# https://setuptools.readthedocs.io/en/latest/pkg_resources.html#requirements-parsing
+# https://www.python.org/dev/peps/pep-0440/
+def main(args):
+ for filename in args:
+ for req in parse_requirements(filename, session=PipSession()):
+ depname = re.sub(r"^(python2?-)?", 'python2-', req.name.lower())
+ if req.link:
+ if req.link.url not in vcspkgs:
+ raise f"no known package for VCS dep {req}"
+ depname = vcspkgs[req.link.url]
+ if req.specifier:
+ for spec in req.specifier:
+ # Hack: Allow some slop with '==', otherwise it would be a
+ # nightmare with keeping things in sync.
+ if spec.operator == "==":
+ if len(spec.version.split('.')) <= 2:
+ spec = Specifier(f"=={spec.version}.*")
+ else:
+ spec = Specifier(f"~={spec.version}")
+
+ if spec.operator == "~=":
+ print(f"{depname}>={spec.version} {depname}<{nextver(spec.version)}")
+ elif spec.operator == "==":
+ if spec.version.endswith(".*"):
+ print(f"{depname}>={spec.version[:-2]} {depname}<{nextver(spec.version)}")
+ else:
+ print(f"{depname}={spec.version}")
+ elif spec.operator == '!=':
+ raise f"version exclusion is not supported: {req}"
+ elif spec.operator in {'<=', '>=', '<', '>'}:
+ print(f"{depname}{spec.operator}{spec.version}")
+ elif spec.operator == "===":
+ print(f"{depname}={spec.version}")
+ else:
+ raise f"unknown specifier operator: {spec.operator}: {req}"
+ else:
+ print(f"{depname}")
+
+
+if __name__ == '__main__':
+ import sys
+ main(sys.argv[1:])