RFL.build 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- RFL.build-1.0.0/PKG-INFO +23 -0
- RFL.build-1.0.0/README.md +3 -0
- RFL.build-1.0.0/RFL.build.egg-info/PKG-INFO +23 -0
- RFL.build-1.0.0/RFL.build.egg-info/SOURCES.txt +14 -0
- RFL.build-1.0.0/RFL.build.egg-info/dependency_links.txt +1 -0
- RFL.build-1.0.0/RFL.build.egg-info/entry_points.txt +3 -0
- RFL.build-1.0.0/RFL.build.egg-info/requires.txt +2 -0
- RFL.build-1.0.0/RFL.build.egg-info/top_level.txt +1 -0
- RFL.build-1.0.0/pyproject.toml +41 -0
- RFL.build-1.0.0/rfl/build/__init__.py +0 -0
- RFL.build-1.0.0/rfl/build/errors.py +11 -0
- RFL.build-1.0.0/rfl/build/installsetup.py +18 -0
- RFL.build-1.0.0/rfl/build/ninja.py +235 -0
- RFL.build-1.0.0/rfl/build/projectversion.py +63 -0
- RFL.build-1.0.0/rfl/build/scripts/setup +100 -0
- RFL.build-1.0.0/setup.cfg +4 -0
RFL.build-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: RFL.build
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Rackslab Foundation Library: build package
|
|
5
|
+
Author-email: Rémi Palancher <remi@rackslab.io>
|
|
6
|
+
License: GPLv3+
|
|
7
|
+
Project-URL: Homepage, https://github.com/rackslab/RFL
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/rackslab/RFL/issues
|
|
9
|
+
Keywords: utility,basic
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: System Administrators
|
|
13
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: System :: Systems Administration
|
|
16
|
+
Requires-Python: >=3.6
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: RFL.core
|
|
19
|
+
Requires-Dist: tomli
|
|
20
|
+
|
|
21
|
+
# RFL: build package
|
|
22
|
+
|
|
23
|
+
Utilities to help backport builds of Python projects.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: RFL.build
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Rackslab Foundation Library: build package
|
|
5
|
+
Author-email: Rémi Palancher <remi@rackslab.io>
|
|
6
|
+
License: GPLv3+
|
|
7
|
+
Project-URL: Homepage, https://github.com/rackslab/RFL
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/rackslab/RFL/issues
|
|
9
|
+
Keywords: utility,basic
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: System Administrators
|
|
13
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: System :: Systems Administration
|
|
16
|
+
Requires-Python: >=3.6
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: RFL.core
|
|
19
|
+
Requires-Dist: tomli
|
|
20
|
+
|
|
21
|
+
# RFL: build package
|
|
22
|
+
|
|
23
|
+
Utilities to help backport builds of Python projects.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
RFL.build.egg-info/PKG-INFO
|
|
4
|
+
RFL.build.egg-info/SOURCES.txt
|
|
5
|
+
RFL.build.egg-info/dependency_links.txt
|
|
6
|
+
RFL.build.egg-info/entry_points.txt
|
|
7
|
+
RFL.build.egg-info/requires.txt
|
|
8
|
+
RFL.build.egg-info/top_level.txt
|
|
9
|
+
rfl/build/__init__.py
|
|
10
|
+
rfl/build/errors.py
|
|
11
|
+
rfl/build/installsetup.py
|
|
12
|
+
rfl/build/ninja.py
|
|
13
|
+
rfl/build/projectversion.py
|
|
14
|
+
rfl/build/scripts/setup
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
rfl
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "RFL.build"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Rackslab Foundation Library: build package"
|
|
9
|
+
license = {text = "GPLv3+"}
|
|
10
|
+
requires-python = ">=3.6"
|
|
11
|
+
keywords = ["utility", "basic"]
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Rémi Palancher", email = "remi@rackslab.io"},
|
|
14
|
+
]
|
|
15
|
+
dependencies = [
|
|
16
|
+
"RFL.core",
|
|
17
|
+
"tomli"
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 5 - Production/Stable",
|
|
21
|
+
"Environment :: Console",
|
|
22
|
+
"Intended Audience :: System Administrators",
|
|
23
|
+
"License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Topic :: System :: Systems Administration",
|
|
26
|
+
]
|
|
27
|
+
readme = "README.md"
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
"Homepage" = "https://github.com/rackslab/RFL"
|
|
31
|
+
"Bug Tracker" = "https://github.com/rackslab/RFL/issues"
|
|
32
|
+
|
|
33
|
+
[project.scripts]
|
|
34
|
+
rfl-install-setup-generator = "rfl.build.installsetup:main"
|
|
35
|
+
rfl-project-version = "rfl.build.projectversion:main"
|
|
36
|
+
|
|
37
|
+
[tool.setuptools.packages.find]
|
|
38
|
+
include = ["rfl.build*"]
|
|
39
|
+
|
|
40
|
+
[tool.setuptools.package-data]
|
|
41
|
+
"rfl.build.scripts" = ["*"]
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Copyright (c) 2023 Rackslab
|
|
2
|
+
#
|
|
3
|
+
# This file is part of RFL.
|
|
4
|
+
#
|
|
5
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import shutil
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main():
|
|
13
|
+
"""Install setup.py script provided by RFL.build package in scripts/ subfolder in
|
|
14
|
+
the current working directory."""
|
|
15
|
+
orig = Path(os.path.realpath(__file__)).parent.joinpath("scripts", "setup")
|
|
16
|
+
dest = Path(os.getcwd()).joinpath("setup.py")
|
|
17
|
+
print(f"Copying file {orig} to {dest}")
|
|
18
|
+
shutil.copy(orig, dest)
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
# Copyright (c) 2011 Google Inc
|
|
2
|
+
# Copyright (c) 2023 Rackslab
|
|
3
|
+
#
|
|
4
|
+
# This file is part of RFL.
|
|
5
|
+
#
|
|
6
|
+
# This file originally comes from Ninja build system source tree:
|
|
7
|
+
# https://github.com/ninja-build/ninja/blob/master/misc/ninja_syntax.py
|
|
8
|
+
#
|
|
9
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
10
|
+
|
|
11
|
+
"""Python module to help generating .ninja files."""
|
|
12
|
+
|
|
13
|
+
import sys
|
|
14
|
+
import io
|
|
15
|
+
import re
|
|
16
|
+
import textwrap
|
|
17
|
+
from pathlib import PurePath
|
|
18
|
+
import subprocess
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def escape_path(word):
|
|
22
|
+
if isinstance(word, PurePath):
|
|
23
|
+
word = str(word)
|
|
24
|
+
return word.replace("$ ", "$$ ").replace(" ", "$ ").replace(":", "$:")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def as_list(input):
|
|
28
|
+
if input is None:
|
|
29
|
+
return []
|
|
30
|
+
if isinstance(input, list):
|
|
31
|
+
return input
|
|
32
|
+
return [input]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def escape(string):
|
|
36
|
+
"""Escape a string such that it can be embedded into a Ninja file without
|
|
37
|
+
further interpretation."""
|
|
38
|
+
assert "\n" not in string, "Ninja syntax does not allow newlines"
|
|
39
|
+
# We only have one special metacharacter: '$'.
|
|
40
|
+
return string.replace("$", "$$")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def expand(string, vars, local_vars={}):
|
|
44
|
+
"""Expand a string containing $vars as Ninja would.
|
|
45
|
+
|
|
46
|
+
Note: doesn't handle the full Ninja variable syntax, but it's enough
|
|
47
|
+
to make configure.py's use of it work.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def exp(m):
|
|
51
|
+
var = m.group(1)
|
|
52
|
+
if var == "$":
|
|
53
|
+
return "$"
|
|
54
|
+
return local_vars.get(var, vars.get(var, ""))
|
|
55
|
+
|
|
56
|
+
return re.sub(r"\$(\$|\w*)", exp, string)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class NinjaBuilder(object):
|
|
60
|
+
def __init__(self, width=512):
|
|
61
|
+
self.output = io.StringIO()
|
|
62
|
+
self.width = width
|
|
63
|
+
|
|
64
|
+
def newline(self):
|
|
65
|
+
self.output.write("\n")
|
|
66
|
+
|
|
67
|
+
def comment(self, text):
|
|
68
|
+
for line in textwrap.wrap(
|
|
69
|
+
text, self.width - 2, break_long_words=False, break_on_hyphens=False
|
|
70
|
+
):
|
|
71
|
+
self.output.write("# " + line + "\n")
|
|
72
|
+
|
|
73
|
+
def variable(self, key, value, indent=0):
|
|
74
|
+
if value is None:
|
|
75
|
+
return
|
|
76
|
+
if isinstance(value, list):
|
|
77
|
+
value = " ".join(filter(None, value)) # Filter out empty strings.
|
|
78
|
+
self._line("%s = %s" % (key, value), indent)
|
|
79
|
+
|
|
80
|
+
def pool(self, name, depth):
|
|
81
|
+
self._line("pool %s" % name)
|
|
82
|
+
self.variable("depth", depth, indent=1)
|
|
83
|
+
|
|
84
|
+
def rule(
|
|
85
|
+
self,
|
|
86
|
+
name,
|
|
87
|
+
command,
|
|
88
|
+
description=None,
|
|
89
|
+
depfile=None,
|
|
90
|
+
generator=False,
|
|
91
|
+
pool=None,
|
|
92
|
+
restat=False,
|
|
93
|
+
rspfile=None,
|
|
94
|
+
rspfile_content=None,
|
|
95
|
+
deps=None,
|
|
96
|
+
):
|
|
97
|
+
self._line("rule %s" % name)
|
|
98
|
+
self.variable("command", command, indent=1)
|
|
99
|
+
if description:
|
|
100
|
+
self.variable("description", description, indent=1)
|
|
101
|
+
if depfile:
|
|
102
|
+
self.variable("depfile", depfile, indent=1)
|
|
103
|
+
if generator:
|
|
104
|
+
self.variable("generator", "1", indent=1)
|
|
105
|
+
if pool:
|
|
106
|
+
self.variable("pool", pool, indent=1)
|
|
107
|
+
if restat:
|
|
108
|
+
self.variable("restat", "1", indent=1)
|
|
109
|
+
if rspfile:
|
|
110
|
+
self.variable("rspfile", rspfile, indent=1)
|
|
111
|
+
if rspfile_content:
|
|
112
|
+
self.variable("rspfile_content", rspfile_content, indent=1)
|
|
113
|
+
if deps:
|
|
114
|
+
self.variable("deps", deps, indent=1)
|
|
115
|
+
|
|
116
|
+
def build(
|
|
117
|
+
self,
|
|
118
|
+
outputs,
|
|
119
|
+
rule,
|
|
120
|
+
inputs=None,
|
|
121
|
+
implicit=None,
|
|
122
|
+
order_only=None,
|
|
123
|
+
variables=None,
|
|
124
|
+
implicit_outputs=None,
|
|
125
|
+
pool=None,
|
|
126
|
+
dyndep=None,
|
|
127
|
+
):
|
|
128
|
+
outputs = as_list(outputs)
|
|
129
|
+
out_outputs = [escape_path(x) for x in outputs]
|
|
130
|
+
all_inputs = [escape_path(x) for x in as_list(inputs)]
|
|
131
|
+
|
|
132
|
+
if implicit:
|
|
133
|
+
implicit = [escape_path(x) for x in as_list(implicit)]
|
|
134
|
+
all_inputs.append("|")
|
|
135
|
+
all_inputs.extend(implicit)
|
|
136
|
+
if order_only:
|
|
137
|
+
order_only = [escape_path(x) for x in as_list(order_only)]
|
|
138
|
+
all_inputs.append("||")
|
|
139
|
+
all_inputs.extend(order_only)
|
|
140
|
+
if implicit_outputs:
|
|
141
|
+
implicit_outputs = [escape_path(x) for x in as_list(implicit_outputs)]
|
|
142
|
+
out_outputs.append("|")
|
|
143
|
+
out_outputs.extend(implicit_outputs)
|
|
144
|
+
|
|
145
|
+
self._line(
|
|
146
|
+
"build %s: %s" % (" ".join(out_outputs), " ".join([rule] + all_inputs))
|
|
147
|
+
)
|
|
148
|
+
if pool is not None:
|
|
149
|
+
self._line(" pool = %s" % pool)
|
|
150
|
+
if dyndep is not None:
|
|
151
|
+
self._line(" dyndep = %s" % dyndep)
|
|
152
|
+
|
|
153
|
+
if variables:
|
|
154
|
+
if isinstance(variables, dict):
|
|
155
|
+
iterator = iter(variables.items())
|
|
156
|
+
else:
|
|
157
|
+
iterator = iter(variables)
|
|
158
|
+
|
|
159
|
+
for key, val in iterator:
|
|
160
|
+
self.variable(key, val, indent=1)
|
|
161
|
+
|
|
162
|
+
return outputs
|
|
163
|
+
|
|
164
|
+
def include(self, path):
|
|
165
|
+
self._line("include %s" % path)
|
|
166
|
+
|
|
167
|
+
def subninja(self, path):
|
|
168
|
+
self._line("subninja %s" % path)
|
|
169
|
+
|
|
170
|
+
def default(self, paths):
|
|
171
|
+
self._line("default %s" % " ".join(as_list(paths)))
|
|
172
|
+
|
|
173
|
+
def _count_dollars_before_index(self, s, i):
|
|
174
|
+
"""Returns the number of '$' characters right in front of s[i]."""
|
|
175
|
+
dollar_count = 0
|
|
176
|
+
dollar_index = i - 1
|
|
177
|
+
while dollar_index > 0 and s[dollar_index] == "$":
|
|
178
|
+
dollar_count += 1
|
|
179
|
+
dollar_index -= 1
|
|
180
|
+
return dollar_count
|
|
181
|
+
|
|
182
|
+
def _line(self, text, indent=0):
|
|
183
|
+
"""Write 'text' word-wrapped at self.width characters."""
|
|
184
|
+
leading_space = " " * indent
|
|
185
|
+
while len(leading_space) + len(text) > self.width:
|
|
186
|
+
# The text is too wide; wrap if possible.
|
|
187
|
+
|
|
188
|
+
# Find the rightmost space that would obey our width constraint and
|
|
189
|
+
# that's not an escaped space.
|
|
190
|
+
available_space = self.width - len(leading_space) - len(" $")
|
|
191
|
+
space = available_space
|
|
192
|
+
while True:
|
|
193
|
+
space = text.rfind(" ", 0, space)
|
|
194
|
+
if space < 0 or self._count_dollars_before_index(text, space) % 2 == 0:
|
|
195
|
+
break
|
|
196
|
+
|
|
197
|
+
if space < 0:
|
|
198
|
+
# No such space; just use the first unescaped space we can find.
|
|
199
|
+
space = available_space - 1
|
|
200
|
+
while True:
|
|
201
|
+
space = text.find(" ", space + 1)
|
|
202
|
+
if (
|
|
203
|
+
space < 0
|
|
204
|
+
or self._count_dollars_before_index(text, space) % 2 == 0
|
|
205
|
+
):
|
|
206
|
+
break
|
|
207
|
+
if space < 0:
|
|
208
|
+
# Give up on breaking.
|
|
209
|
+
break
|
|
210
|
+
|
|
211
|
+
self.output.write(leading_space + text[0:space] + " $\n")
|
|
212
|
+
text = text[space + 1 :]
|
|
213
|
+
|
|
214
|
+
# Subsequent lines are continuations, so indent them.
|
|
215
|
+
leading_space = " " * (indent + 2)
|
|
216
|
+
|
|
217
|
+
self.output.write(leading_space + text + "\n")
|
|
218
|
+
|
|
219
|
+
def run(self):
|
|
220
|
+
self.output.seek(0)
|
|
221
|
+
try:
|
|
222
|
+
subprocess.run(
|
|
223
|
+
["ninja", "-f", "/dev/stdin"], input=self.output.read().encode()
|
|
224
|
+
)
|
|
225
|
+
except subprocess.CalledProcessError as err:
|
|
226
|
+
print(
|
|
227
|
+
"Error while running ninja:\n"
|
|
228
|
+
f" exit code: {err.returncode}\n"
|
|
229
|
+
f" stdout: {err.stdout}\n"
|
|
230
|
+
f" stderr: {err.stderr}",
|
|
231
|
+
file=sys.stderr,
|
|
232
|
+
)
|
|
233
|
+
sys.exit(1)
|
|
234
|
+
finally:
|
|
235
|
+
self.output.close()
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Copyright (c) 2023 Rackslab
|
|
2
|
+
#
|
|
3
|
+
# This file is part of RFL.
|
|
4
|
+
#
|
|
5
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
This tiny utility loads pyproject.toml file of current working directory project,
|
|
9
|
+
looking for this file in parents directory recursively up to filesystem root. If the
|
|
10
|
+
file is found, print the version of the project on stdout. Else, print an error.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import sys
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
# First try to import Python standard toml library (available in Python 3.11+) and
|
|
17
|
+
# fallback to external library.
|
|
18
|
+
try:
|
|
19
|
+
import tomllib
|
|
20
|
+
except ImportError:
|
|
21
|
+
import tomli as tomllib
|
|
22
|
+
|
|
23
|
+
from .errors import BuildError
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def project_version():
|
|
27
|
+
current_dir = Path.cwd()
|
|
28
|
+
found = False
|
|
29
|
+
while True:
|
|
30
|
+
pyproject_path = current_dir.joinpath("pyproject.toml")
|
|
31
|
+
if pyproject_path.exists():
|
|
32
|
+
found = True
|
|
33
|
+
break
|
|
34
|
+
else:
|
|
35
|
+
# Stop iteration when filesystem root is reached.
|
|
36
|
+
if str(current_dir) == current_dir.root:
|
|
37
|
+
break
|
|
38
|
+
# Jump to parent directory.
|
|
39
|
+
current_dir = current_dir.parent
|
|
40
|
+
|
|
41
|
+
if not found:
|
|
42
|
+
raise BuildError(
|
|
43
|
+
"Unable to find project pyproject.toml file of current working directory",
|
|
44
|
+
)
|
|
45
|
+
content = tomllib.load(open(pyproject_path, "rb"))
|
|
46
|
+
try:
|
|
47
|
+
return content["project"]["version"]
|
|
48
|
+
except KeyError as err:
|
|
49
|
+
raise BuildError(
|
|
50
|
+
f"Unable to extract version from project file {pyproject_path}"
|
|
51
|
+
) from err
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def main():
|
|
55
|
+
try:
|
|
56
|
+
print(project_version())
|
|
57
|
+
except BuildError as err:
|
|
58
|
+
print(str(err), file=sys.stderr)
|
|
59
|
+
sys.exit(1)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
main()
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Copyright (c) 2023 Rackslab
|
|
2
|
+
#
|
|
3
|
+
# This file is part of RFL.
|
|
4
|
+
#
|
|
5
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
This setup.py loads parameter defined in pyproject.toml and calls setuptools.setup()
|
|
9
|
+
with these parameters. This script is especially useful to build modern PEP 518 Python
|
|
10
|
+
projects that provide pyproject.toml with old versions of pip/python (eg. python 3.6)
|
|
11
|
+
without PEP 518 support.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import sys
|
|
15
|
+
import os
|
|
16
|
+
|
|
17
|
+
from setuptools import setup, find_packages
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
import tomllib
|
|
21
|
+
except ImportError:
|
|
22
|
+
import tomli as tomllib
|
|
23
|
+
|
|
24
|
+
header = "rfl-build"
|
|
25
|
+
|
|
26
|
+
with open("pyproject.toml", "rb") as fh:
|
|
27
|
+
pyproject = tomllib.load(fh)
|
|
28
|
+
|
|
29
|
+
# Nothing much can be done by the script.
|
|
30
|
+
if "project" not in pyproject:
|
|
31
|
+
print(f"{header}: project section not found, leaving.")
|
|
32
|
+
sys.exit(0)
|
|
33
|
+
|
|
34
|
+
# Initialize dict of additional options
|
|
35
|
+
kwargs = {}
|
|
36
|
+
|
|
37
|
+
if "scripts" in pyproject["project"]:
|
|
38
|
+
kwargs["entry_points"] = {
|
|
39
|
+
"console_scripts": [
|
|
40
|
+
f"{executable}={caller}"
|
|
41
|
+
for executable, caller in pyproject["project"]["scripts"].items()
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# Python Packaging User Guide suggests using find_namespace_packages(…) to support
|
|
46
|
+
# namespace packages:
|
|
47
|
+
#
|
|
48
|
+
# https://packaging.python.org/en/latest/guides/packaging-namespace-packages/#native-namespace-packages
|
|
49
|
+
#
|
|
50
|
+
# Unfortunately, this function is not support in setuptools < v40.1.0 that is provided
|
|
51
|
+
# on systems with Python 3.6 where this setup.py script is required (el8). The
|
|
52
|
+
# alternative solution is to explicitely list the packages to install. Then the
|
|
53
|
+
# following logic detects if there is a native namespace (when one topfolder declared in
|
|
54
|
+
# [tool.setuptools.packages.find] include directive does not contain an __init__.py). In
|
|
55
|
+
# this case, the subpackages are explicity declared (without wildcard) in setup(). If no
|
|
56
|
+
# namespace is detected, the packages are automatically detected with find_packages().
|
|
57
|
+
|
|
58
|
+
autofind = True
|
|
59
|
+
packages = []
|
|
60
|
+
for include in pyproject["tool"]["setuptools"]["packages"]["find"]["include"]:
|
|
61
|
+
if "." not in include:
|
|
62
|
+
continue
|
|
63
|
+
topfolder = include.split(".", 1)[0]
|
|
64
|
+
if "__init__.py" not in os.listdir(topfolder):
|
|
65
|
+
autofind = False
|
|
66
|
+
packages.append(include.replace("*", ""))
|
|
67
|
+
|
|
68
|
+
if autofind:
|
|
69
|
+
kwargs["packages"] = find_packages()
|
|
70
|
+
else:
|
|
71
|
+
kwargs["packages"] = packages
|
|
72
|
+
|
|
73
|
+
print(f"{header}: packages: {kwargs['packages']}")
|
|
74
|
+
|
|
75
|
+
if "package-data" in pyproject["tool"]["setuptools"]:
|
|
76
|
+
kwargs["package_data"] = {
|
|
77
|
+
package: data
|
|
78
|
+
for package, data in pyproject["tool"]["setuptools"]["package-data"].items()
|
|
79
|
+
}
|
|
80
|
+
kwargs["include_package_data"] = True
|
|
81
|
+
print(f"{header}: package data {kwargs['package_data']}")
|
|
82
|
+
|
|
83
|
+
if "optional-dependencies" in pyproject["project"]:
|
|
84
|
+
kwargs["extras_require"] = {
|
|
85
|
+
extra: deps
|
|
86
|
+
for extra, deps in pyproject["project"]["optional-dependencies"].items()
|
|
87
|
+
}
|
|
88
|
+
print(f"{header}: extras require {kwargs['extras_require']}")
|
|
89
|
+
|
|
90
|
+
setup(
|
|
91
|
+
name=pyproject["project"]["name"],
|
|
92
|
+
version=pyproject["project"]["version"],
|
|
93
|
+
author=pyproject["project"]["authors"][0]["name"],
|
|
94
|
+
author_email=pyproject["project"]["authors"][0]["email"],
|
|
95
|
+
license=pyproject["project"]["license"]["text"],
|
|
96
|
+
url=pyproject["project"]["urls"]["Homepage"],
|
|
97
|
+
platforms=["GNU/Linux"],
|
|
98
|
+
install_requires=pyproject["project"]["dependencies"],
|
|
99
|
+
**kwargs,
|
|
100
|
+
)
|