Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 46 additions & 75 deletions py2pack/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,12 @@
import json
import os
import pprint
import pwd
import re
import sys
import warnings

import jinja2
import pypi_search.search

import requests
from metaextract import utils as meta_utils

Expand All @@ -39,7 +38,8 @@
parse_pyproject, get_setuptools_scripts,
get_metadata)

from email import parser
from py2pack.parse import (fetch_local_data, fix_info, get_homepage,
get_user_name)


def replace_string(output_string, replaces):
Expand Down Expand Up @@ -67,33 +67,6 @@ def pypi_json(project, release=None):
return pypimeta


def pypi_text_file(pkg_info_path):
with open(pkg_info_path, 'r') as pkg_info_file:
pkg_info_lines = parser.Parser().parse(pkg_info_file)
pkg_info_dict = {}
for key, value in pkg_info_lines.items():
key = key.lower().replace('-', '_')
if key in {'classifiers', 'requires_dist', 'provides_extra'}:
val = pkg_info_dict.get(key)
if val is None:
val = []
pkg_info_dict[key] = val
val.append(value)
else:
pkg_info_dict[key] = value
return {'info': pkg_info_dict, 'urls': []}


def pypi_json_file(file_path):
with open(file_path, 'r') as json_file:
js = json.load(json_file)
if 'info' not in js:
js = {'info': js}
if 'urls' not in js:
js['urls'] = []
return js


def _get_template_dirs():
"""existing directories where to search for jinja2 templates. The order
is important. The first found template from the first found dir wins!"""
Expand Down Expand Up @@ -121,14 +94,8 @@ def list_packages(args=None):
print(package)


def search(args):
print('searching for package {0}...'.format(args.name))
for hit in pypi_search.search.find_packages(args.name):
print('found {0}-{1}'.format(hit['name'], hit['version']))


def show(args):
fetch_data(args)
fetch_data(args, trylocal=True)
print('showing package {0}...'.format(args.fetched_data['info']['name']))
pprint.pprint(args.fetched_data)

Expand Down Expand Up @@ -239,11 +206,7 @@ def _canonicalize_setup_data(data):
data["console_scripts"] = list(dict.fromkeys(console_scripts))

# Standards says, that keys must be lowercase but not even PyPA adheres to it
homepage = (get_pyproject_table(data, 'project.urls.homepage') or
get_pyproject_table(data, 'project.urls.Homepage') or
get_pyproject_table(data, 'project.urls.Source') or
get_pyproject_table(data, 'project.urls.GitHub') or
get_pyproject_table(data, 'project.urls.Repository') or
homepage = (get_homepage(get_pyproject_table(data, 'project.urls')) or
data.get('home_page', None))
if homepage:
data['home_page'] = homepage
Expand Down Expand Up @@ -363,7 +326,7 @@ def generate(args):
warnings.warn("the '--run' switch is deprecated and a noop",
DeprecationWarning)

fetch_local_data(args)
fetch_data(args, trylocal=True)
if not args.template:
args.template = file_template_list()[0]
if not args.filename:
Expand All @@ -373,7 +336,7 @@ def generate(args):
durl = newest_download_url(args)
source_url = data['source_url'] = (args.source_url or (durl and durl['url']))
data['year'] = datetime.datetime.now().year # set current year
data['user_name'] = pwd.getpwuid(os.getuid())[4] # set system user (packager)
data['user_name'] = get_user_name() # set system user (packager)
data['summary_no_ending_dot'] = re.sub(r'(.*)\.', r'\g<1>', data.get('summary')) if data.get('summary') else ""

# If package name supplied on command line differs in case from PyPI's one
Expand All @@ -392,15 +355,24 @@ def generate(args):
if tarball_file:
break

if tarball_file: # get some more info from that
# localarchive argument was set by fetch_local_data method, and, if not empty, then exists in filesystem
localarchive = args.localarchive

if tarball_file and not localarchive: # get some more info from that
tarball_file = tarball_file[0]
else:
tarball_file = localarchive

if not tarball_file:
tarball_file = args.name + '-' + args.version + '.tar.gz'

if os.path.exists(tarball_file):
_augment_data_from_tarball(args, tarball_file, data)

else:
warnings.warn("No tarball for {} in version {} found. Valuable "
"information for the generation might be missing."
"".format(args.name, args.version))
tarball_file = args.name + '-' + args.version + '.zip'

if not source_url:
data['source_url'] = os.path.basename(tarball_file)
Expand All @@ -409,6 +381,7 @@ def generate(args):

env = _prepare_template_env(_get_template_dirs())
template = env.get_template(args.template)
data.update(args.options) # update data with custom options
result = template.render(data).encode('utf-8') # render template and encode properly
outfile = open(args.filename, 'wb') # write result to spec file
try:
Expand All @@ -417,31 +390,22 @@ def generate(args):
outfile.close()


def fetch_local_data(args):
localfile = args.localfile
local = args.local

if not localfile and local:
localfile = os.path.join(f'{args.name}.egg-info', 'PKG-INFO')
if os.path.isfile(localfile):
try:
data = pypi_json_file(localfile)
except json.decoder.JSONDecodeError:
data = pypi_text_file(localfile)
args.fetched_data = data
args.version = args.fetched_data['info']['version']
return
fetch_data(args)


def fetch_data(args):
args.fetched_data = pypi_json(args.name, args.version)
urls = args.fetched_data.get('urls', [])
if len(urls) == 0:
print(f"unable to find a suitable release for {args.name}!")
sys.exit(1)
else:
args.version = args.fetched_data['info']['version'] # return current release number
def fetch_data(args, trylocal=False):
if trylocal:
trylocal = fetch_local_data(args)
if not trylocal:
args.fetched_data = pypi_json(args.name, args.version)
urls = args.fetched_data.get('urls', [])
if len(urls) == 0:
print(f"unable to find a suitable release for {args.name}!")
sys.exit(1)
data_info = args.fetched_data["info"]
fix_info(data_info)
# set version if absent
args.version = data_info['version']
# set name if absent
if not args.name:
args.name = data_info['name']


def newest_download_url(args):
Expand Down Expand Up @@ -480,13 +444,11 @@ def main():
parser_list = subparsers.add_parser('list', help='list all packages on PyPI')
parser_list.set_defaults(func=list_packages)

parser_search = subparsers.add_parser('search', help='search for packages on PyPI')
parser_search.add_argument('name', help='package name (with optional version)')
parser_search.set_defaults(func=search)

parser_show = subparsers.add_parser('show', help='show metadata for package')
parser_show.add_argument('name', help='package name')
parser_show.add_argument('version', nargs='?', help='package version (optional)')
parser_show.add_argument('--local', action='store_true', help='show metadata from local package')
parser_show.add_argument('--localfile', default='', help='path to the local PKG-INFO or json metadata')
parser_show.set_defaults(func=show)

parser_fetch = subparsers.add_parser('fetch', help='download package source tarball from PyPI')
Expand All @@ -500,6 +462,7 @@ def main():
parser_generate.add_argument('version', nargs='?', help='package version (optional)')
parser_generate.add_argument('--source-url', default=None, help='source url')
parser_generate.add_argument('--source-glob', help='source glob template')
parser_generate.add_argument('--setopt', action="append", help='An KEY=VALUE option (optional)', default=[])
parser_generate.add_argument('--local', action='store_true', help='build from local package')
parser_generate.add_argument('--localfile', default='', help='path to the local PKG-INFO or json metadata')
parser_generate.add_argument('-t', '--template', choices=file_template_list(), default='opensuse.spec', help='file template')
Expand All @@ -526,6 +489,14 @@ def main():

if 'func' not in args:
sys.exit(parser.print_help())
if args.func == generate:
options = args.options = {}
for opt in args.setopt:
if '=' in opt:
key, value = opt.split('=', 1)
options[key] = value
else:
options[opt] = True
args.func(args)


Expand Down
Loading