bin2whl 1.0.0__py3-none-any.whl
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.
- bin2whl/__init__.py +24 -0
- bin2whl/__main__.py +28 -0
- bin2whl/_version.py +1 -0
- bin2whl/argbuilder.py +172 -0
- bin2whl/cli.py +369 -0
- bin2whl/config.py +275 -0
- bin2whl/metadata.py +161 -0
- bin2whl/version.py +35 -0
- bin2whl/wheel_builder.py +266 -0
- bin2whl-1.0.0.dist-info/METADATA +154 -0
- bin2whl-1.0.0.dist-info/RECORD +14 -0
- bin2whl-1.0.0.dist-info/WHEEL +4 -0
- bin2whl-1.0.0.dist-info/entry_points.txt +2 -0
- bin2whl-1.0.0.dist-info/licenses/LICENSE +24 -0
bin2whl/__init__.py
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# ----------------------------------------------------------------------------------------
|
|
2
|
+
# __init__.py
|
|
3
|
+
# -----------
|
|
4
|
+
#
|
|
5
|
+
# bin2whl package initialisation.
|
|
6
|
+
#
|
|
7
|
+
# (c) 2026 WaterJuice — Unlicense; see LICENSE in the project root.
|
|
8
|
+
#
|
|
9
|
+
# Authors
|
|
10
|
+
# -------
|
|
11
|
+
# bena (via Claude)
|
|
12
|
+
#
|
|
13
|
+
# Version History
|
|
14
|
+
# ---------------
|
|
15
|
+
# Mar 2026 - Created
|
|
16
|
+
# ----------------------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
"""bin2whl: Build Python wheels from pre-compiled binaries."""
|
|
19
|
+
|
|
20
|
+
from bin2whl.version import VERSION_STR
|
|
21
|
+
|
|
22
|
+
__all__ = ["__version__"]
|
|
23
|
+
|
|
24
|
+
__version__ = VERSION_STR
|
bin2whl/__main__.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# ----------------------------------------------------------------------------------------
|
|
2
|
+
# __main__.py
|
|
3
|
+
# -----------
|
|
4
|
+
#
|
|
5
|
+
# Entry point for python -m bin2whl.
|
|
6
|
+
#
|
|
7
|
+
# (c) 2026 WaterJuice — Unlicense; see LICENSE in the project root.
|
|
8
|
+
#
|
|
9
|
+
# Authors
|
|
10
|
+
# -------
|
|
11
|
+
# bena (via Claude)
|
|
12
|
+
#
|
|
13
|
+
# Version History
|
|
14
|
+
# ---------------
|
|
15
|
+
# Mar 2026 - Created
|
|
16
|
+
# ----------------------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
import sys
|
|
19
|
+
|
|
20
|
+
MIN_PYTHON = (3, 12)
|
|
21
|
+
if sys.version_info < MIN_PYTHON:
|
|
22
|
+
print(f"Python {MIN_PYTHON[0]}.{MIN_PYTHON[1]}+ is required.", file=sys.stderr)
|
|
23
|
+
sys.exit(1)
|
|
24
|
+
|
|
25
|
+
from bin2whl.cli import main # noqa: E402
|
|
26
|
+
|
|
27
|
+
if __name__ == "__main__":
|
|
28
|
+
raise SystemExit(main())
|
bin2whl/_version.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.0"
|
bin2whl/argbuilder.py
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# ----------------------------------------------------------------------------------------
|
|
2
|
+
# argbuilder.py
|
|
3
|
+
# -------------
|
|
4
|
+
#
|
|
5
|
+
# Argument parser wrapper with deferred execution. Provides a thin layer over
|
|
6
|
+
# argparse for consistent CLI argument handling.
|
|
7
|
+
#
|
|
8
|
+
# (c) 2026 WaterJuice — Unlicense; see LICENSE in the project root.
|
|
9
|
+
#
|
|
10
|
+
# Authors
|
|
11
|
+
# -------
|
|
12
|
+
# bena (via Claude)
|
|
13
|
+
#
|
|
14
|
+
# Version History
|
|
15
|
+
# ---------------
|
|
16
|
+
# Mar 2026 - Created
|
|
17
|
+
# ----------------------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
# ----------------------------------------------------------------------------------------
|
|
20
|
+
# Imports
|
|
21
|
+
# ----------------------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
import argparse
|
|
24
|
+
from typing import Any
|
|
25
|
+
|
|
26
|
+
# ----------------------------------------------------------------------------------------
|
|
27
|
+
# Types
|
|
28
|
+
# ----------------------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
Namespace = argparse.Namespace
|
|
31
|
+
|
|
32
|
+
# ----------------------------------------------------------------------------------------
|
|
33
|
+
# Classes
|
|
34
|
+
# ----------------------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ArgsParser:
|
|
38
|
+
"""
|
|
39
|
+
Thin wrapper over argparse.ArgumentParser with a simplified interface.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
# ------------------------------------------------------------------------------------
|
|
43
|
+
def __init__(
|
|
44
|
+
self,
|
|
45
|
+
prog: str,
|
|
46
|
+
description: str,
|
|
47
|
+
version: str,
|
|
48
|
+
) -> None:
|
|
49
|
+
"""
|
|
50
|
+
Initialise the argument parser.
|
|
51
|
+
|
|
52
|
+
Parameters:
|
|
53
|
+
prog: Program name.
|
|
54
|
+
description: Program description shown in help.
|
|
55
|
+
version: Version string shown with --version.
|
|
56
|
+
"""
|
|
57
|
+
self._parser = argparse.ArgumentParser(
|
|
58
|
+
prog=prog,
|
|
59
|
+
description=description,
|
|
60
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
61
|
+
)
|
|
62
|
+
self._parser.add_argument(
|
|
63
|
+
"--version",
|
|
64
|
+
action="version",
|
|
65
|
+
version=version,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# ------------------------------------------------------------------------------------
|
|
69
|
+
def add_argument(self, *args: Any, **kwargs: Any) -> argparse.Action:
|
|
70
|
+
"""
|
|
71
|
+
Add an argument to the parser. Passes through to argparse.
|
|
72
|
+
|
|
73
|
+
Parameters:
|
|
74
|
+
args: Positional arguments for argparse.
|
|
75
|
+
kwargs: Keyword arguments for argparse.
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
The created Action.
|
|
79
|
+
"""
|
|
80
|
+
return self._parser.add_argument(*args, **kwargs)
|
|
81
|
+
|
|
82
|
+
# ------------------------------------------------------------------------------------
|
|
83
|
+
def add_argument_group(self, title: str) -> "ArgGroup":
|
|
84
|
+
"""
|
|
85
|
+
Add a named argument group for organising help output.
|
|
86
|
+
|
|
87
|
+
Parameters:
|
|
88
|
+
title: Group heading shown in help.
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
An ArgGroup wrapper.
|
|
92
|
+
"""
|
|
93
|
+
group = self._parser.add_argument_group(title)
|
|
94
|
+
return ArgGroup(group)
|
|
95
|
+
|
|
96
|
+
# ------------------------------------------------------------------------------------
|
|
97
|
+
def add_mutex_group(self) -> "MutexGroup":
|
|
98
|
+
"""
|
|
99
|
+
Add a mutually exclusive argument group.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
A MutexGroup wrapper.
|
|
103
|
+
"""
|
|
104
|
+
group = self._parser.add_mutually_exclusive_group()
|
|
105
|
+
return MutexGroup(group)
|
|
106
|
+
|
|
107
|
+
# ------------------------------------------------------------------------------------
|
|
108
|
+
def parse(self, argv: list[str]) -> Namespace:
|
|
109
|
+
"""
|
|
110
|
+
Parse arguments and return the namespace.
|
|
111
|
+
|
|
112
|
+
Parameters:
|
|
113
|
+
argv: List of argument strings (without program name).
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
Parsed argument namespace.
|
|
117
|
+
"""
|
|
118
|
+
return self._parser.parse_args(argv)
|
|
119
|
+
|
|
120
|
+
# ------------------------------------------------------------------------------------
|
|
121
|
+
def error(self, message: str) -> None:
|
|
122
|
+
"""
|
|
123
|
+
Print an error message and exit.
|
|
124
|
+
|
|
125
|
+
Parameters:
|
|
126
|
+
message: The error message to display.
|
|
127
|
+
"""
|
|
128
|
+
self._parser.error(message)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class ArgGroup:
|
|
132
|
+
"""Wrapper for a named argument group."""
|
|
133
|
+
|
|
134
|
+
# ------------------------------------------------------------------------------------
|
|
135
|
+
def __init__(self, group: argparse._ArgumentGroup) -> None: # pyright: ignore[reportPrivateUsage]
|
|
136
|
+
self._group = group
|
|
137
|
+
|
|
138
|
+
# ------------------------------------------------------------------------------------
|
|
139
|
+
def add_argument(self, *args: Any, **kwargs: Any) -> argparse.Action:
|
|
140
|
+
"""
|
|
141
|
+
Add an argument to the group. Passes through to argparse.
|
|
142
|
+
|
|
143
|
+
Parameters:
|
|
144
|
+
args: Positional arguments for argparse.
|
|
145
|
+
kwargs: Keyword arguments for argparse.
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
The created Action.
|
|
149
|
+
"""
|
|
150
|
+
return self._group.add_argument(*args, **kwargs)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
class MutexGroup:
|
|
154
|
+
"""Wrapper for a mutually exclusive argument group."""
|
|
155
|
+
|
|
156
|
+
# ------------------------------------------------------------------------------------
|
|
157
|
+
def __init__(self, group: argparse._MutuallyExclusiveGroup) -> None: # pyright: ignore[reportPrivateUsage]
|
|
158
|
+
self._group = group
|
|
159
|
+
|
|
160
|
+
# ------------------------------------------------------------------------------------
|
|
161
|
+
def add_argument(self, *args: Any, **kwargs: Any) -> argparse.Action:
|
|
162
|
+
"""
|
|
163
|
+
Add an argument to the mutex group. Passes through to argparse.
|
|
164
|
+
|
|
165
|
+
Parameters:
|
|
166
|
+
args: Positional arguments for argparse.
|
|
167
|
+
kwargs: Keyword arguments for argparse.
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
The created Action.
|
|
171
|
+
"""
|
|
172
|
+
return self._group.add_argument(*args, **kwargs)
|
bin2whl/cli.py
ADDED
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
# ----------------------------------------------------------------------------------------
|
|
2
|
+
# cli.py
|
|
3
|
+
# ------
|
|
4
|
+
#
|
|
5
|
+
# Command-line interface entry point for bin2whl. Supports building Python wheels
|
|
6
|
+
# from pre-compiled binaries, either via a wheel.json config file or CLI arguments.
|
|
7
|
+
#
|
|
8
|
+
# (c) 2026 WaterJuice — Unlicense; see LICENSE in the project root.
|
|
9
|
+
#
|
|
10
|
+
# Authors
|
|
11
|
+
# -------
|
|
12
|
+
# bena (via Claude)
|
|
13
|
+
#
|
|
14
|
+
# Version History
|
|
15
|
+
# ---------------
|
|
16
|
+
# Mar 2026 - Created
|
|
17
|
+
# Apr 2026 - Added multi-binary support
|
|
18
|
+
# ----------------------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
# ----------------------------------------------------------------------------------------
|
|
21
|
+
# Imports
|
|
22
|
+
# ----------------------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
import sys
|
|
25
|
+
import traceback
|
|
26
|
+
from pathlib import Path
|
|
27
|
+
from bin2whl.config import DEFAULT_OUTPUT_DIR
|
|
28
|
+
from bin2whl.config import load_config
|
|
29
|
+
from bin2whl.version import VERSION_STR
|
|
30
|
+
from bin2whl.wheel_builder import BinarySpec
|
|
31
|
+
from bin2whl.wheel_builder import build_wheel
|
|
32
|
+
from .argbuilder import ArgsParser
|
|
33
|
+
from .argbuilder import Namespace
|
|
34
|
+
|
|
35
|
+
# ----------------------------------------------------------------------------------------
|
|
36
|
+
# Constants
|
|
37
|
+
# ----------------------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
LICENSE_TEXT = """\
|
|
40
|
+
This is free and unencumbered software released into the public domain.
|
|
41
|
+
|
|
42
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
43
|
+
distribute this software, either in source code form or as a compiled
|
|
44
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
|
45
|
+
means.
|
|
46
|
+
|
|
47
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
|
48
|
+
of this software dedicate any and all copyright interest in the
|
|
49
|
+
software to the public domain. We make this dedication for the benefit
|
|
50
|
+
of the public at large and to the detriment of our heirs and
|
|
51
|
+
successors. We intend this dedication to be an overt act of
|
|
52
|
+
relinquishment in perpetuity of all present and future rights to this
|
|
53
|
+
software under copyright law.
|
|
54
|
+
|
|
55
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
56
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
57
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
58
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
59
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
60
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
61
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
62
|
+
|
|
63
|
+
For more information, please refer to <https://unlicense.org>"""
|
|
64
|
+
|
|
65
|
+
EXAMPLE_CONFIG = """\
|
|
66
|
+
Single binary per platform:
|
|
67
|
+
|
|
68
|
+
{
|
|
69
|
+
"name": "your-tool",
|
|
70
|
+
"version": "0.1.0",
|
|
71
|
+
"description": "A CLI tool packaged for PyPI",
|
|
72
|
+
"author": "Your Name",
|
|
73
|
+
"license": "MIT",
|
|
74
|
+
"binaries": {
|
|
75
|
+
"linux_x86_64": "dist/your-tool-linux-x86_64",
|
|
76
|
+
"linux_arm64": "dist/your-tool-linux-arm64",
|
|
77
|
+
"macos_arm64": "dist/your-tool-macos-arm64",
|
|
78
|
+
"windows_amd64": "dist/your-tool-win-x86_64.exe"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
Multiple binaries per platform:
|
|
83
|
+
|
|
84
|
+
{
|
|
85
|
+
"name": "your-suite",
|
|
86
|
+
"version": "0.1.0",
|
|
87
|
+
"binaries": {
|
|
88
|
+
"linux_x86_64": [
|
|
89
|
+
{"name": "your-server", "path": "dist/server-linux-x86_64"},
|
|
90
|
+
{"name": "your-client", "path": "dist/client-linux-x86_64"}
|
|
91
|
+
],
|
|
92
|
+
"macos_arm64": [
|
|
93
|
+
{"name": "your-server", "path": "dist/server-darwin-arm64"},
|
|
94
|
+
{"name": "your-client", "path": "dist/client-darwin-arm64"}
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
}"""
|
|
98
|
+
|
|
99
|
+
PLATFORMS_TEXT = """\
|
|
100
|
+
Platform aliases (short names that expand to standard wheel tags):
|
|
101
|
+
|
|
102
|
+
linux_x86_64 → manylinux_2_17_x86_64
|
|
103
|
+
linux_amd64 → manylinux_2_17_x86_64
|
|
104
|
+
linux_aarch64 → manylinux_2_17_aarch64
|
|
105
|
+
linux_arm64 → manylinux_2_17_aarch64
|
|
106
|
+
macos_x86_64 → macosx_10_9_x86_64
|
|
107
|
+
macos_amd64 → macosx_10_9_x86_64
|
|
108
|
+
macos_arm64 → macosx_11_0_arm64
|
|
109
|
+
macos_aarch64 → macosx_11_0_arm64
|
|
110
|
+
windows_amd64 → win_amd64
|
|
111
|
+
windows_x86_64 → win_amd64
|
|
112
|
+
windows_arm64 → win_arm64
|
|
113
|
+
|
|
114
|
+
Any valid wheel platform tag is also accepted directly (e.g. macosx_14_0_arm64)."""
|
|
115
|
+
|
|
116
|
+
# ----------------------------------------------------------------------------------------
|
|
117
|
+
# Functions
|
|
118
|
+
# ----------------------------------------------------------------------------------------
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# ----------------------------------------------------------------------------------------
|
|
122
|
+
def parse_args(argv: list[str]) -> Namespace:
|
|
123
|
+
"""Parse command-line arguments."""
|
|
124
|
+
p = ArgsParser(
|
|
125
|
+
prog="bin2whl",
|
|
126
|
+
description=(
|
|
127
|
+
f"bin2whl: {VERSION_STR}\n"
|
|
128
|
+
"(c) 2026 WaterJuice. Unlicense.\n\n"
|
|
129
|
+
"Build Python wheels from pre-compiled binaries."
|
|
130
|
+
),
|
|
131
|
+
version=f"bin2whl: {VERSION_STR}\npython: {sys.version.split()[0]}",
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
p.add_argument(
|
|
135
|
+
"--license",
|
|
136
|
+
action="version",
|
|
137
|
+
version=LICENSE_TEXT,
|
|
138
|
+
help="show license and exit",
|
|
139
|
+
)
|
|
140
|
+
p.add_argument(
|
|
141
|
+
"--example-config",
|
|
142
|
+
action="version",
|
|
143
|
+
version=EXAMPLE_CONFIG,
|
|
144
|
+
help="print an example wheel.json and exit",
|
|
145
|
+
)
|
|
146
|
+
p.add_argument(
|
|
147
|
+
"--platforms",
|
|
148
|
+
action="version",
|
|
149
|
+
version=PLATFORMS_TEXT,
|
|
150
|
+
help="list supported platform tags and exit",
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
common_group = p.add_argument_group("common options")
|
|
154
|
+
common_group.add_argument(
|
|
155
|
+
"--version-str",
|
|
156
|
+
"-v",
|
|
157
|
+
default=None,
|
|
158
|
+
dest="pkg_version",
|
|
159
|
+
help="package version (required for single binary mode, overrides config)",
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
config_group = p.add_argument_group("config file mode")
|
|
163
|
+
config_group.add_argument(
|
|
164
|
+
"--config",
|
|
165
|
+
"-c",
|
|
166
|
+
default=None,
|
|
167
|
+
help="path to config file (e.g. wheel.json)",
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
single_group = p.add_argument_group("single binary mode")
|
|
171
|
+
single_group.add_argument(
|
|
172
|
+
"--name",
|
|
173
|
+
"-n",
|
|
174
|
+
default=None,
|
|
175
|
+
help="package name",
|
|
176
|
+
)
|
|
177
|
+
single_group.add_argument(
|
|
178
|
+
"--binary",
|
|
179
|
+
"-b",
|
|
180
|
+
default=None,
|
|
181
|
+
help="path to binary file",
|
|
182
|
+
)
|
|
183
|
+
single_group.add_argument(
|
|
184
|
+
"--platform",
|
|
185
|
+
"-p",
|
|
186
|
+
default=None,
|
|
187
|
+
help="platform tag (see --platforms)",
|
|
188
|
+
)
|
|
189
|
+
single_group.add_argument(
|
|
190
|
+
"--description",
|
|
191
|
+
"-d",
|
|
192
|
+
default="",
|
|
193
|
+
help="package description",
|
|
194
|
+
)
|
|
195
|
+
single_group.add_argument(
|
|
196
|
+
"--author",
|
|
197
|
+
"-a",
|
|
198
|
+
default="",
|
|
199
|
+
help="author name",
|
|
200
|
+
)
|
|
201
|
+
single_group.add_argument(
|
|
202
|
+
"--author-email",
|
|
203
|
+
"-e",
|
|
204
|
+
default="",
|
|
205
|
+
help="author email",
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
output_group = p.add_argument_group("output")
|
|
209
|
+
output_group.add_argument(
|
|
210
|
+
"--output-dir",
|
|
211
|
+
"-o",
|
|
212
|
+
default=None,
|
|
213
|
+
help="output directory for wheel files (default: wheels)",
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
return p.parse(argv)
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
# ----------------------------------------------------------------------------------------
|
|
220
|
+
def main(argv: list[str] | None = None) -> int:
|
|
221
|
+
"""
|
|
222
|
+
Main entry point for the bin2whl CLI.
|
|
223
|
+
|
|
224
|
+
Parameters:
|
|
225
|
+
argv: Command line arguments (without program name). If None, uses sys.argv[1:].
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
Exit code (0 for success, non-zero for error)
|
|
229
|
+
"""
|
|
230
|
+
if argv is None:
|
|
231
|
+
argv = sys.argv[1:]
|
|
232
|
+
|
|
233
|
+
try:
|
|
234
|
+
return _main_inner(argv)
|
|
235
|
+
except KeyboardInterrupt:
|
|
236
|
+
print()
|
|
237
|
+
print("---- Manually Terminated ----")
|
|
238
|
+
print()
|
|
239
|
+
return 1
|
|
240
|
+
except SystemExit:
|
|
241
|
+
raise
|
|
242
|
+
except BaseException as e:
|
|
243
|
+
t = "-----------------------------------------------------------------------------\n"
|
|
244
|
+
t += "UNHANDLED EXCEPTION OCCURRED!!\n"
|
|
245
|
+
t += "\n"
|
|
246
|
+
t += traceback.format_exc()
|
|
247
|
+
t += "\n"
|
|
248
|
+
t += f"EXCEPTION: {type(e)} {e}\n"
|
|
249
|
+
t += "-----------------------------------------------------------------------------\n"
|
|
250
|
+
t += "\n"
|
|
251
|
+
print(t, file=sys.stderr)
|
|
252
|
+
return 1
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
# ----------------------------------------------------------------------------------------
|
|
256
|
+
def _main_inner(argv: list[str]) -> int:
|
|
257
|
+
"""Inner main function that does the actual work."""
|
|
258
|
+
args = parse_args(argv)
|
|
259
|
+
|
|
260
|
+
# Determine mode: single binary or config file
|
|
261
|
+
single_binary_args = [args.name, args.binary, args.platform]
|
|
262
|
+
has_single_args = any(a is not None for a in single_binary_args)
|
|
263
|
+
all_single_args = (
|
|
264
|
+
all(a is not None for a in single_binary_args) and args.pkg_version is not None
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
if has_single_args and not all_single_args:
|
|
268
|
+
print(
|
|
269
|
+
"Error: --name, --version-str, --binary, and --platform are all required "
|
|
270
|
+
"for single binary mode.",
|
|
271
|
+
file=sys.stderr,
|
|
272
|
+
)
|
|
273
|
+
return 1
|
|
274
|
+
|
|
275
|
+
if has_single_args:
|
|
276
|
+
return _build_single(args)
|
|
277
|
+
|
|
278
|
+
# Config file mode requires --config
|
|
279
|
+
if args.config is not None:
|
|
280
|
+
return _build_from_config(args)
|
|
281
|
+
|
|
282
|
+
# No arguments given — show help
|
|
283
|
+
parse_args(["--help"])
|
|
284
|
+
return 0
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
# ----------------------------------------------------------------------------------------
|
|
288
|
+
def _build_single(args: Namespace) -> int:
|
|
289
|
+
"""
|
|
290
|
+
Build a single wheel from CLI arguments.
|
|
291
|
+
|
|
292
|
+
Parameters:
|
|
293
|
+
args: Parsed command-line arguments.
|
|
294
|
+
|
|
295
|
+
Returns:
|
|
296
|
+
Exit code.
|
|
297
|
+
"""
|
|
298
|
+
output_dir = Path(args.output_dir) if args.output_dir else Path(DEFAULT_OUTPUT_DIR)
|
|
299
|
+
|
|
300
|
+
try:
|
|
301
|
+
wheel_path = build_wheel(
|
|
302
|
+
binary_path=Path(args.binary),
|
|
303
|
+
name=args.name,
|
|
304
|
+
version=args.pkg_version,
|
|
305
|
+
platform=args.platform,
|
|
306
|
+
output_dir=output_dir,
|
|
307
|
+
description=args.description,
|
|
308
|
+
author=args.author,
|
|
309
|
+
author_email=args.author_email,
|
|
310
|
+
)
|
|
311
|
+
except (FileNotFoundError, IsADirectoryError, ValueError) as e:
|
|
312
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
313
|
+
return 1
|
|
314
|
+
|
|
315
|
+
print(f"Built: {wheel_path}")
|
|
316
|
+
return 0
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
# ----------------------------------------------------------------------------------------
|
|
320
|
+
def _build_from_config(args: Namespace) -> int:
|
|
321
|
+
"""
|
|
322
|
+
Build wheels from a wheel.json configuration file.
|
|
323
|
+
|
|
324
|
+
Parameters:
|
|
325
|
+
args: Parsed command-line arguments.
|
|
326
|
+
|
|
327
|
+
Returns:
|
|
328
|
+
Exit code.
|
|
329
|
+
"""
|
|
330
|
+
config_path = Path(args.config)
|
|
331
|
+
|
|
332
|
+
try:
|
|
333
|
+
config = load_config(config_path)
|
|
334
|
+
except (FileNotFoundError, IsADirectoryError, ValueError) as e:
|
|
335
|
+
print(f"Error: {e}", file=sys.stderr)
|
|
336
|
+
return 1
|
|
337
|
+
|
|
338
|
+
version = args.pkg_version if args.pkg_version else config.version
|
|
339
|
+
if not version:
|
|
340
|
+
print(
|
|
341
|
+
"Error: version is required. Provide it in the config file or with --version-str.",
|
|
342
|
+
file=sys.stderr,
|
|
343
|
+
)
|
|
344
|
+
return 1
|
|
345
|
+
output_dir = Path(args.output_dir) if args.output_dir else Path(config.output_dir)
|
|
346
|
+
built_count = 0
|
|
347
|
+
|
|
348
|
+
for binary_mapping in config.binaries:
|
|
349
|
+
specs = [BinarySpec(name=e.name, path=e.path) for e in binary_mapping.entries]
|
|
350
|
+
wheel_path = build_wheel(
|
|
351
|
+
name=config.name,
|
|
352
|
+
version=version,
|
|
353
|
+
platform=binary_mapping.platform,
|
|
354
|
+
output_dir=output_dir,
|
|
355
|
+
description=config.description,
|
|
356
|
+
author=config.author,
|
|
357
|
+
author_email=config.author_email,
|
|
358
|
+
license_name=config.license_name,
|
|
359
|
+
homepage=config.homepage,
|
|
360
|
+
python_requires=config.python_requires,
|
|
361
|
+
classifiers=config.classifiers,
|
|
362
|
+
readme_content=config.readme_content,
|
|
363
|
+
binaries=specs,
|
|
364
|
+
)
|
|
365
|
+
print(f"Built: {wheel_path}")
|
|
366
|
+
built_count += 1
|
|
367
|
+
|
|
368
|
+
print(f"\n{built_count} wheel(s) built in {output_dir}/")
|
|
369
|
+
return 0
|