Source code for lilac2.pypi2pkgbuild

import json
import urllib.request
from typing import (
  Dict, Optional, Iterable, List, Any, Tuple,
)

template = '''\
_name={name}
pkgname={pkgname}
pkgver={pkgver}
pkgrel=1
pkgdesc="{summary}"
arch=({arch})
url="{home_page}"
license=({license})
{depends}
{conflicts}{provides}{source}
sha256sums=('{sha256sum}')
{prepare}
build() {{
{build}
}}

package() {{
{package}

  # make sure we don't install any world-writable or root-readable-only files
  # we shouldn't need to fix ownership as we extract tarballs as a non-root user
  # https://github.com/pypa/setuptools/issues/1328
  # https://github.com/LonamiWebs/Telethon/issues/1605
  chmod u=rwX,go=rX -R "$pkgdir"
  # make sure we don't install annoying files
  local _site_packages=$(python -c "import site; print(site.getsitepackages()[0])")
  rm -rf "$pkgdir/$_site_packages/tests/"
}}
{check}
'''

pkg_license_tmpl = '''\
  install -Dm644 {license_file} "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
'''

pkg_pip_tmpl = '''\
  cd "$srcdir"
  pip install '{whl}' --root="$pkgdir" --no-deps --install-option="--optimize=1"
'''

class PyPIException(Exception): pass

def to_sharray(arr: Iterable[str]) -> str:
  return ' '.join(f"'{x}'" for x in arr)

def get_pypi_info(name: str) -> Dict[str, Any]:
  url = f'https://pypi.org/pypi/{name}/json'
  res = urllib.request.urlopen(url)
  data = res.read().decode('utf-8')
  j = json.loads(data)
  return j

[docs] def gen_pkgbuild( pypi_name: str, pkgname: Optional[str] = None, depends: Optional[List[str]] = None, python2: bool = False, arch: Optional[Iterable[str]] = None, makedepends: Optional[List[str]] = None, optdepends: Optional[List[str]] = None, depends_setuptools: bool = False, check: Optional[str] = None, provides: Optional[Iterable[str]] = None, conflicts: Optional[Iterable[str]] = None, license: Optional[str] = None, license_file: Optional[str] = None, prepare: Optional[str] = None, pep517: bool = False, ) -> Tuple[str, str]: j = get_pypi_info(pypi_name) version = j['info']['version'] source_release: List[Dict[str, Any]] = [] whl_release: List[Dict[str, Any]] = [] source_release = [ x for x in j['releases'][version] if x['packagetype'] == 'sdist'] if not source_release: whl_release = [ x for x in j['releases'][version] if x['packagetype'] == 'bdist_wheel'] if not whl_release: raise PyPIException('no release of known type') if not source_release and license_file: raise PyPIException('no source code available so cannot install license_file') makedepends2 = makedepends or [] if whl_release: makedepends2.append('python-pip') depends2 = depends or ['python'] if depends_setuptools: depends2.append('python-setuptools') elif not pep517: makedepends2.append('python-setuptools') if pep517: makedepends2.extend(['python-build', 'python-installer', 'python-wheel']) depends_str = [] if depends2: depends_str.append(f'depends=({to_sharray(depends2)})') if makedepends2: depends_str.append( f'makedepends=({to_sharray(makedepends2)})') if optdepends: depends_str.append( f'optdepends=({to_sharray(optdepends)})') src_dir = '$_name-$pkgver' if source_release: r = source_release[-1] tarball = r['filename'] src_dir = tarball.rsplit('.tar', 1)[0] # tarball name may be different from pypi name, e.g. django-post-office # Use "predictable" URL instead of `r['url']` to make AUR users happy... source_line = 'source=("https://files.pythonhosted.org/packages/source/${_name::1}/${_name}/%s")' % tarball if pep517: build_code = f'''\ cd "$srcdir/{src_dir}" python -m build --wheel --no-isolation ''' package_code = f'''\ cd "$srcdir/{src_dir}" python -m installer --destdir="$pkgdir" dist/*.whl ''' else: build_code = f'''\ cd "$srcdir/{src_dir}" python3 setup.py build ''' package_code = f'''\ cd "$srcdir/{src_dir}" python3 setup.py install --root=$pkgdir --optimize=1 --skip-build ''' if license_file: package_code += pkg_license_tmpl.format( license_file = license_file) elif whl_release: r = whl_release[-1] whl_pyver = r['python_version'] whl = r['url'].rsplit('/')[-1] source_line = f'source=("https://files.pythonhosted.org/packages/{whl_pyver}/${{_name::1}}/$_name/{whl}")' build_code = ' true' package_code = pkg_pip_tmpl.format(whl=whl) if check is not None: if check == 'nose': depends_str.append("checkdepends=('python-nose')") check_code = f''' check() {{ cd "$srcdir/{src_dir}" python -m unittest discover tests }}''' else: raise ValueError('unrecognized check value', check) else: check_code = '' if prepare is not None: prepare_code = f''' prepare() {{ cd "$srcdir/{src_dir}" {prepare} }} ''' else: prepare_code = '' vars1 = { 'name': j['info']['name'], 'pkgname': pkgname or f'python-{pypi_name.lower()}', 'pkgver': version, 'summary': j['info']['summary'], 'arch': to_sharray(arch) if arch else 'any', 'home_page': j['info']['home_page'] or j['info']['project_urls'].get('Homepage', ''), 'license': license or "'%s'" % j['info']['license'], 'depends': '\n'.join(depends_str), 'provides': f'provides=({to_sharray(provides)})\n' if provides else '', 'conflicts': f'conflicts=({to_sharray(conflicts)})\n' if conflicts else '', 'source': source_line, 'sha256sum': r['digests']['sha256'], 'build': build_code.rstrip(), 'package': package_code.rstrip(), 'check': check_code.rstrip(), 'prepare': prepare_code, } pkgbuild = template.format_map(vars1) return version, pkgbuild