Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add archiving option, fix exceptions, caused by multiline content in rpm spec files, fix shebangs, which are not required #214

Closed
wants to merge 6 commits into from
Closed
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
84 changes: 71 additions & 13 deletions py2pack/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright (c) 2013, Sascha Peilicke <[email protected]>
#
# Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -38,8 +35,24 @@
from py2pack.utils import (_get_archive_filelist, get_pyproject_table,
parse_pyproject, get_setuptools_scripts,
get_metadata)

import io
from email import parser
from packaging.requirements import Requirement

try:
import libarchive
except ModuleNotFoundError:
libarchive = None

try:
import distro
DEFAULT_TEMPLATE = {
'fedora': 'fedora.spec',
'debian': 'opensuse.dsc',
'mageia': 'mageia.spec'
}.get(distro.id(), 'opensuse.spec')
except ModuleNotFoundError:
DEFAULT_TEMPLATE = 'opensuse.spec'


def replace_string(output_string, replaces):
Expand All @@ -51,6 +64,7 @@ def replace_string(output_string, replaces):

warnings.simplefilter('always', DeprecationWarning)


SPDX_LICENSES_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'spdx_license_map.json')
with open(SPDX_LICENSES_FILE, 'r') as fp:
SPDX_LICENSES = json.load(fp)
Expand All @@ -69,7 +83,11 @@ def pypi_json(project, release=None):

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)
return pypi_text_stream(pkg_info_file)


def pypi_text_stream(pkg_info_stream):
pkg_info_lines = parser.Parser().parse(pkg_info_stream)
pkg_info_dict = {}
for key, value in pkg_info_lines.items():
key = key.lower().replace('-', '_')
Expand All @@ -86,14 +104,33 @@ def pypi_text_file(pkg_info_path):

def pypi_json_file(file_path):
with open(file_path, 'r') as json_file:
js = json.load(json_file)
return pypi_json_stream(json_file)


def pypi_json_stream(json_stream):
js = json.load(json_stream)
if 'info' not in js:
js = {'info': js}
if 'urls' not in js:
js['urls'] = []
return js


def pypi_archive_file(file_path):
if libarchive is None:
return None
try:
with libarchive.file_reader(file_path) as archive:
for entry in archive:
# Check if the entry's pathname matches the target filename
if entry.pathname == 'PKG-INFO':
return pypi_text_stream(io.StringIO(entry.read().decode()))
else:
return None
except Exception:
return None


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 @@ -417,6 +454,23 @@ def generate(args):
outfile.close()


def fix_data(data):
extra_from_req = re.compile(r'''\bextra\s+==\s+["']([^"']+)["']''')
extras = []
data_info = data["info"]
requires_dist = data_info["requires_dist"] or []
provides_extra = data_info["provides_extra"] or []
if requires_dist is not None:
for required_dist in requires_dist:
req = Requirement(required_dist)
if found := re.search(extra_from_req, str(req.marker)):
extras.append(found.group(1))
provides_extra = list(sorted(set([*extras, *provides_extra])))
data_info["requires_dist"] = requires_dist
data_info["provides_extra"] = provides_extra
data_info["classifiers"] = (data_info["classifiers"] or [])


def fetch_local_data(args):
localfile = args.localfile
local = args.local
Expand All @@ -427,21 +481,25 @@ def fetch_local_data(args):
try:
data = pypi_json_file(localfile)
except json.decoder.JSONDecodeError:
data = pypi_text_file(localfile)
data = pypi_archive_file(localfile)
if data is None:
data = pypi_text_file(localfile)
args.fetched_data = data
args.version = args.fetched_data['info']['version']
return
fetch_data(args)
fix_data(data)
else:
fetch_data(args)


def fetch_data(args):
args.fetched_data = pypi_json(args.name, args.version)
urls = args.fetched_data.get('urls', [])
data = args.fetched_data = pypi_json(args.name, args.version)
urls = 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
args.version = data['info']['version'] # return current release number
fix_data(data)


def newest_download_url(args):
Expand Down Expand Up @@ -502,7 +560,7 @@ def main():
parser_generate.add_argument('--source-glob', help='source glob template')
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')
parser_generate.add_argument('-t', '--template', choices=file_template_list(), default=DEFAULT_TEMPLATE, help='file template')
parser_generate.add_argument('-f', '--filename', help='spec filename (optional)')
# TODO (toabctl): remove this is a later release
parser_generate.add_argument(
Expand Down
8 changes: 4 additions & 4 deletions py2pack/templates/fedora.spec
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
Name: python-%{pypi_name}
Version: {{ version }}
Release: %autorelease
Summary: {{ summary }}
Summary: {{ summary|replace('\n','') }}

# Check if the automatically generated License and its spelling is correct for Fedora
# https://docs.fedoraproject.org/en-US/packaging-guidelines/LicensingGuidelines/
License: {{ license }}
URL: {{ home_page }}
Source: {{ source_url|replace(version, '%{version}') }}
License: {{ license|replace('\n','') }}
URL: {{ home_page|replace('\n','') }}
Source: {{ source_url|replace(version, '%{version}')|replace('\n','') }}

BuildRequires: pyproject-rpm-macros
BuildRequires: python-devel
Expand Down
8 changes: 4 additions & 4 deletions py2pack/templates/mageia.spec
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
Name: python-%{mod_name}
Version: {{ version }}
Release: %mkrel 1
Url: {{ home_page }}
Summary: {{ summary }}
License: {{ license }}
Url: {{ home_page|replace('\n','') }}
Summary: {{ summary|replace('\n','') }}
License: {{ license|replace('\n','') }}
Group: Development/Python
Source: {{ source_url|replace(version, '%{version}') }}
Source: {{ source_url|replace(version, '%{version}')|replace('\n','') }}
BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
BuildRequires: python-devel
{%- for req in requires %}
Expand Down
8 changes: 4 additions & 4 deletions py2pack/templates/opensuse-legacy.spec
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
Name: python-{{ name }}
Version: {{ version }}
Release: 0
Summary: {{ summary_no_ending_dot|default(summary, true) }}
License: {{ license }}
URL: {{ home_page }}
Source: {{ source_url|replace(version, '%{version}') }}
Summary: {{ summary_no_ending_dot|default(summary, true)|replace('\n','') }}
License: {{ license|replace('\n','') }}
URL: {{ home_page|replace('\n','') }}
Source: {{ source_url|replace(version, '%{version}')|replace('\n','') }}
BuildRequires: python-setuptools
{%- if install_requires and install_requires is not none %}
{%- for req in install_requires|sort %}
Expand Down
8 changes: 4 additions & 4 deletions py2pack/templates/opensuse.spec
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
Name: python-{{ name }}
Version: {{ version }}
Release: 0
Summary: {{ summary_no_ending_dot|default(summary, true) }}
License: {{ license }}
URL: {{ home_page }}
Source: {{ source_url|replace(version, '%{version}') }}
Summary: {{ summary_no_ending_dot|default(summary, true)|replace('\n','') }}
License: {{ license|replace('\n','') }}
URL: {{ home_page|replace('\n','') }}
Source: {{ source_url|replace(version, '%{version}')|replace('\n','') }}
BuildRequires: python-rpm-macros
{%- set build_requires_plus_pip = ((build_requires if build_requires and build_requires is not none else []) +
['pip']) %}
Expand Down
9 changes: 9 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ classifiers = [
]
dependencies = [
"Jinja2",
"distro",
"libarchive-c",
"backports.entry_points_selectable",
"build",
"setuptools",
Expand All @@ -38,13 +40,20 @@ dependencies = [
"requests",
"tomli; python_version < '3.11'",
]

requires-python = ">=3.6"
dynamic = ['version']


[project.urls]
homepage = "http://github.com/openSUSE/py2pack"

[project.optional-dependencies]
service = [
"libarchive-c",
"distro",
]

[project.scripts]
py2pack = "py2pack:main"

Expand Down
2 changes: 1 addition & 1 deletion test/examples/poetry-opensuse-augmented.spec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#
# spec file for package python-poetry
#
# Copyright (c) 2024 SUSE LLC
# Copyright (c) __YEAR__ SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
Expand Down
74 changes: 0 additions & 74 deletions test/examples/py2pack-fedora-augmented.spec

This file was deleted.

Loading
Loading