pystand 2.16__tar.gz → 2.18__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.
- {pystand-2.16 → pystand-2.18}/Makefile +1 -0
- {pystand-2.16 → pystand-2.18}/PKG-INFO +42 -19
- pystand-2.16/pystand.egg-info/PKG-INFO → pystand-2.18/README.md +38 -34
- {pystand-2.16 → pystand-2.18}/pyproject.toml +3 -1
- pystand-2.16/README.md → pystand-2.18/pystand.egg-info/PKG-INFO +57 -17
- pystand-2.18/pystand.egg-info/requires.txt +9 -0
- {pystand-2.16 → pystand-2.18}/pystand.py +72 -53
- pystand-2.16/pystand.egg-info/requires.txt +0 -5
- {pystand-2.16 → pystand-2.18}/.gitignore +0 -0
- {pystand-2.16 → pystand-2.18}/pystand.egg-info/SOURCES.txt +0 -0
- {pystand-2.16 → pystand-2.18}/pystand.egg-info/dependency_links.txt +0 -0
- {pystand-2.16 → pystand-2.18}/pystand.egg-info/entry_points.txt +0 -0
- {pystand-2.16 → pystand-2.18}/pystand.egg-info/top_level.txt +0 -0
- {pystand-2.16 → pystand-2.18}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: pystand
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.18
|
4
4
|
Summary: Install Python versions from python-build-standalone project
|
5
5
|
Author-email: Mark Blakeney <mark.blakeney@bullet-systems.net>
|
6
6
|
License-Expression: GPL-3.0-or-later
|
@@ -12,8 +12,10 @@ Description-Content-Type: text/markdown
|
|
12
12
|
Requires-Dist: argcomplete
|
13
13
|
Requires-Dist: packaging
|
14
14
|
Requires-Dist: platformdirs
|
15
|
+
Requires-Dist: argparse-from-file
|
15
16
|
Requires-Dist: pygithub
|
16
|
-
Requires-Dist:
|
17
|
+
Requires-Dist: certifi
|
18
|
+
Requires-Dist: zstandard; python_version < "3.14"
|
17
19
|
|
18
20
|
## PYSTAND - Install Python Versions From The Python-Build-Standalone Project
|
19
21
|
[](https://pypi.org/project/pystand/)
|
@@ -24,14 +26,14 @@ installation, and update of pre-built Python versions from the
|
|
24
26
|
[`python-build-standalone`][pbs] project. The following commands are
|
25
27
|
provided:
|
26
28
|
|
27
|
-
|Command |Description
|
28
|
-
|
29
|
-
|`install`|Install one or more versions from a python-build-standalone release
|
30
|
-
|`update` (or `upgrade`) |Update one, more, or all versions to another release
|
31
|
-
|`remove` (or `uninstall`) |Remove/uninstall one, more, or all versions
|
32
|
-
|`list` |List installed versions and show which have an update available
|
33
|
-
|`show` |Show versions available from a release
|
34
|
-
|`path` |Show path prefix to installed version base directory
|
29
|
+
|Command |Description |
|
30
|
+
|---------|--------------------------------------------------------------------|
|
31
|
+
|`install`|Install one or more versions from a python-build-standalone release.|
|
32
|
+
|`update` (or `upgrade`) |Update one, more, or all versions to another release.|
|
33
|
+
|`remove` (or `uninstall`) |Remove/uninstall one, more, or all versions.|
|
34
|
+
|`list` |List installed versions and show which have an update available.|
|
35
|
+
|`show` |Show versions available from a release.|
|
36
|
+
|`path` |Show path prefix to installed version base directory.|
|
35
37
|
|
36
38
|
By default, Python versions are sourced from the latest
|
37
39
|
`python-build-standalone` [release][pbs-rel] available (e.g.
|
@@ -130,7 +132,7 @@ Type `pystand` or `pystand -h` to view the usage summary:
|
|
130
132
|
usage: pystand [-h] [-D DISTRIBUTION] [-P PREFIX_DIR] [-C CACHE_DIR]
|
131
133
|
[-M CACHE_MINUTES] [--purge-days PURGE_DAYS]
|
132
134
|
[--github-access-token GITHUB_ACCESS_TOKEN] [--no-strip]
|
133
|
-
[-V]
|
135
|
+
[--cert {system,certifi,none}] [-V]
|
134
136
|
{install,update,upgrade,remove,uninstall,list,show,path,cache} ...
|
135
137
|
|
136
138
|
Command line tool to download, install, and update pre-built Python versions
|
@@ -146,22 +148,25 @@ options:
|
|
146
148
|
distributions.
|
147
149
|
-P, --prefix-dir PREFIX_DIR
|
148
150
|
specify prefix dir for storing versions. Default is
|
149
|
-
"$HOME/.local/share/pystand"
|
151
|
+
"$HOME/.local/share/pystand".
|
150
152
|
-C, --cache-dir CACHE_DIR
|
151
153
|
specify cache dir for downloads. Default is
|
152
|
-
"$HOME/.cache/pystand"
|
154
|
+
"$HOME/.cache/pystand".
|
153
155
|
-M, --cache-minutes CACHE_MINUTES
|
154
156
|
cache latest YYYYMMDD release tag fetch for this many
|
155
157
|
minutes, before rechecking for latest. Default is 60
|
156
|
-
minutes
|
158
|
+
minutes.
|
157
159
|
--purge-days PURGE_DAYS
|
158
160
|
cache YYYYMMDD release file lists and downloads for
|
159
161
|
this number of days after last version referencing
|
160
|
-
that release is removed. Default is 90 days
|
162
|
+
that release is removed. Default is 90 days.
|
161
163
|
--github-access-token GITHUB_ACCESS_TOKEN
|
162
164
|
optional Github access token. Can specify to reduce
|
163
165
|
rate limiting.
|
164
166
|
--no-strip do not strip downloaded binaries
|
167
|
+
--cert {system,certifi,none}
|
168
|
+
specify which SSL certificates to use for HTTPS
|
169
|
+
requests. Default="system".
|
165
170
|
-V, --version just show pystand version
|
166
171
|
|
167
172
|
Commands:
|
@@ -562,9 +567,8 @@ anything after on a line) are ignored. Type `pystand` to see all
|
|
562
567
|
supported options.
|
563
568
|
|
564
569
|
The global options: `--distribution`, `--prefix-dir`, `--cache-dir`,
|
565
|
-
`--cache-minutes`, `--purge-days`, `--github-access-token`,
|
566
|
-
`--
|
567
|
-
as defaults.
|
570
|
+
`--cache-minutes`, `--purge-days`, `--github-access-token`, `--no-strip`,
|
571
|
+
`--cert` are the only sensible candidates to consider setting as defaults.
|
568
572
|
|
569
573
|
## Github API Rate Limiting
|
570
574
|
|
@@ -579,6 +583,24 @@ either a Github "fine-grained" or "classic" token. Specify the token on
|
|
579
583
|
the command line with `--github-access-token`, or set that as a [default
|
580
584
|
option](#command-default-options).
|
581
585
|
|
586
|
+
## HTTPS Certificate Verification
|
587
|
+
|
588
|
+
A global option `--cert` is provided to specify which SSL certificates to use
|
589
|
+
for HTTPS requests. This is useful if you are running `pystand` in an
|
590
|
+
environment where the system certificates are not available, or you want to use
|
591
|
+
the bundled [`certifi`][certifi] certificates instead.
|
592
|
+
|
593
|
+
The available options are:
|
594
|
+
|
595
|
+
|Option |Description
|
596
|
+
|-------- |------------
|
597
|
+
|`system` |Use system certificates (as used normally by Python). This is the default.|
|
598
|
+
|`certifi`|Use the [`certifi`][certifi] package, i.e. use the certificates bundled within the application.|
|
599
|
+
|`none` |Perform unverified https requests (best to avoid using this).|
|
600
|
+
|
601
|
+
Specify the option on the command line with `--cert`, or set that as a [default
|
602
|
+
option](#command-default-options).
|
603
|
+
|
582
604
|
## Command Line Tab Completion
|
583
605
|
|
584
606
|
Command line shell [tab
|
@@ -598,7 +620,7 @@ either version 3 of the License, or any later version. This program is
|
|
598
620
|
distributed in the hope that it will be useful, but WITHOUT ANY
|
599
621
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
600
622
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License at
|
601
|
-
<
|
623
|
+
<https://opensource.org/license/gpl-3-0> for more details.
|
602
624
|
|
603
625
|
[pystand]: https://github.com/bulletmark/pystand
|
604
626
|
[pbs]: https://github.com/astral-sh/python-build-standalone
|
@@ -612,5 +634,6 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License at
|
|
612
634
|
[hatch]: https://hatch.pypa.io/
|
613
635
|
[hatchpy]: https://hatch.pypa.io/latest/tutorials/python/manage/
|
614
636
|
[ryepy]: https://rye.astral.sh/guide/toolchains/#fetching-toolchains
|
637
|
+
[certifi]: https://pypi.org/project/certifi/
|
615
638
|
|
616
639
|
<!-- vim: se ai syn=markdown: -->
|
@@ -1,20 +1,3 @@
|
|
1
|
-
Metadata-Version: 2.4
|
2
|
-
Name: pystand
|
3
|
-
Version: 2.16
|
4
|
-
Summary: Install Python versions from python-build-standalone project
|
5
|
-
Author-email: Mark Blakeney <mark.blakeney@bullet-systems.net>
|
6
|
-
License-Expression: GPL-3.0-or-later
|
7
|
-
Project-URL: Homepage, https://github.com/bulletmark/pystand
|
8
|
-
Keywords: python-build-standalone,pyenv,hatch,pdm
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
10
|
-
Requires-Python: >=3.8
|
11
|
-
Description-Content-Type: text/markdown
|
12
|
-
Requires-Dist: argcomplete
|
13
|
-
Requires-Dist: packaging
|
14
|
-
Requires-Dist: platformdirs
|
15
|
-
Requires-Dist: pygithub
|
16
|
-
Requires-Dist: zstandard
|
17
|
-
|
18
1
|
## PYSTAND - Install Python Versions From The Python-Build-Standalone Project
|
19
2
|
[](https://pypi.org/project/pystand/)
|
20
3
|
[](https://aur.archlinux.org/packages/pystand/)
|
@@ -24,14 +7,14 @@ installation, and update of pre-built Python versions from the
|
|
24
7
|
[`python-build-standalone`][pbs] project. The following commands are
|
25
8
|
provided:
|
26
9
|
|
27
|
-
|Command |Description
|
28
|
-
|
29
|
-
|`install`|Install one or more versions from a python-build-standalone release
|
30
|
-
|`update` (or `upgrade`) |Update one, more, or all versions to another release
|
31
|
-
|`remove` (or `uninstall`) |Remove/uninstall one, more, or all versions
|
32
|
-
|`list` |List installed versions and show which have an update available
|
33
|
-
|`show` |Show versions available from a release
|
34
|
-
|`path` |Show path prefix to installed version base directory
|
10
|
+
|Command |Description |
|
11
|
+
|---------|--------------------------------------------------------------------|
|
12
|
+
|`install`|Install one or more versions from a python-build-standalone release.|
|
13
|
+
|`update` (or `upgrade`) |Update one, more, or all versions to another release.|
|
14
|
+
|`remove` (or `uninstall`) |Remove/uninstall one, more, or all versions.|
|
15
|
+
|`list` |List installed versions and show which have an update available.|
|
16
|
+
|`show` |Show versions available from a release.|
|
17
|
+
|`path` |Show path prefix to installed version base directory.|
|
35
18
|
|
36
19
|
By default, Python versions are sourced from the latest
|
37
20
|
`python-build-standalone` [release][pbs-rel] available (e.g.
|
@@ -130,7 +113,7 @@ Type `pystand` or `pystand -h` to view the usage summary:
|
|
130
113
|
usage: pystand [-h] [-D DISTRIBUTION] [-P PREFIX_DIR] [-C CACHE_DIR]
|
131
114
|
[-M CACHE_MINUTES] [--purge-days PURGE_DAYS]
|
132
115
|
[--github-access-token GITHUB_ACCESS_TOKEN] [--no-strip]
|
133
|
-
[-V]
|
116
|
+
[--cert {system,certifi,none}] [-V]
|
134
117
|
{install,update,upgrade,remove,uninstall,list,show,path,cache} ...
|
135
118
|
|
136
119
|
Command line tool to download, install, and update pre-built Python versions
|
@@ -146,22 +129,25 @@ options:
|
|
146
129
|
distributions.
|
147
130
|
-P, --prefix-dir PREFIX_DIR
|
148
131
|
specify prefix dir for storing versions. Default is
|
149
|
-
"$HOME/.local/share/pystand"
|
132
|
+
"$HOME/.local/share/pystand".
|
150
133
|
-C, --cache-dir CACHE_DIR
|
151
134
|
specify cache dir for downloads. Default is
|
152
|
-
"$HOME/.cache/pystand"
|
135
|
+
"$HOME/.cache/pystand".
|
153
136
|
-M, --cache-minutes CACHE_MINUTES
|
154
137
|
cache latest YYYYMMDD release tag fetch for this many
|
155
138
|
minutes, before rechecking for latest. Default is 60
|
156
|
-
minutes
|
139
|
+
minutes.
|
157
140
|
--purge-days PURGE_DAYS
|
158
141
|
cache YYYYMMDD release file lists and downloads for
|
159
142
|
this number of days after last version referencing
|
160
|
-
that release is removed. Default is 90 days
|
143
|
+
that release is removed. Default is 90 days.
|
161
144
|
--github-access-token GITHUB_ACCESS_TOKEN
|
162
145
|
optional Github access token. Can specify to reduce
|
163
146
|
rate limiting.
|
164
147
|
--no-strip do not strip downloaded binaries
|
148
|
+
--cert {system,certifi,none}
|
149
|
+
specify which SSL certificates to use for HTTPS
|
150
|
+
requests. Default="system".
|
165
151
|
-V, --version just show pystand version
|
166
152
|
|
167
153
|
Commands:
|
@@ -562,9 +548,8 @@ anything after on a line) are ignored. Type `pystand` to see all
|
|
562
548
|
supported options.
|
563
549
|
|
564
550
|
The global options: `--distribution`, `--prefix-dir`, `--cache-dir`,
|
565
|
-
`--cache-minutes`, `--purge-days`, `--github-access-token`,
|
566
|
-
`--
|
567
|
-
as defaults.
|
551
|
+
`--cache-minutes`, `--purge-days`, `--github-access-token`, `--no-strip`,
|
552
|
+
`--cert` are the only sensible candidates to consider setting as defaults.
|
568
553
|
|
569
554
|
## Github API Rate Limiting
|
570
555
|
|
@@ -579,6 +564,24 @@ either a Github "fine-grained" or "classic" token. Specify the token on
|
|
579
564
|
the command line with `--github-access-token`, or set that as a [default
|
580
565
|
option](#command-default-options).
|
581
566
|
|
567
|
+
## HTTPS Certificate Verification
|
568
|
+
|
569
|
+
A global option `--cert` is provided to specify which SSL certificates to use
|
570
|
+
for HTTPS requests. This is useful if you are running `pystand` in an
|
571
|
+
environment where the system certificates are not available, or you want to use
|
572
|
+
the bundled [`certifi`][certifi] certificates instead.
|
573
|
+
|
574
|
+
The available options are:
|
575
|
+
|
576
|
+
|Option |Description
|
577
|
+
|-------- |------------
|
578
|
+
|`system` |Use system certificates (as used normally by Python). This is the default.|
|
579
|
+
|`certifi`|Use the [`certifi`][certifi] package, i.e. use the certificates bundled within the application.|
|
580
|
+
|`none` |Perform unverified https requests (best to avoid using this).|
|
581
|
+
|
582
|
+
Specify the option on the command line with `--cert`, or set that as a [default
|
583
|
+
option](#command-default-options).
|
584
|
+
|
582
585
|
## Command Line Tab Completion
|
583
586
|
|
584
587
|
Command line shell [tab
|
@@ -598,7 +601,7 @@ either version 3 of the License, or any later version. This program is
|
|
598
601
|
distributed in the hope that it will be useful, but WITHOUT ANY
|
599
602
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
600
603
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License at
|
601
|
-
<
|
604
|
+
<https://opensource.org/license/gpl-3-0> for more details.
|
602
605
|
|
603
606
|
[pystand]: https://github.com/bulletmark/pystand
|
604
607
|
[pbs]: https://github.com/astral-sh/python-build-standalone
|
@@ -612,5 +615,6 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License at
|
|
612
615
|
[hatch]: https://hatch.pypa.io/
|
613
616
|
[hatchpy]: https://hatch.pypa.io/latest/tutorials/python/manage/
|
614
617
|
[ryepy]: https://rye.astral.sh/guide/toolchains/#fetching-toolchains
|
618
|
+
[certifi]: https://pypi.org/project/certifi/
|
615
619
|
|
616
620
|
<!-- vim: se ai syn=markdown: -->
|
@@ -1,3 +1,22 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: pystand
|
3
|
+
Version: 2.18
|
4
|
+
Summary: Install Python versions from python-build-standalone project
|
5
|
+
Author-email: Mark Blakeney <mark.blakeney@bullet-systems.net>
|
6
|
+
License-Expression: GPL-3.0-or-later
|
7
|
+
Project-URL: Homepage, https://github.com/bulletmark/pystand
|
8
|
+
Keywords: python-build-standalone,pyenv,hatch,pdm
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
10
|
+
Requires-Python: >=3.8
|
11
|
+
Description-Content-Type: text/markdown
|
12
|
+
Requires-Dist: argcomplete
|
13
|
+
Requires-Dist: packaging
|
14
|
+
Requires-Dist: platformdirs
|
15
|
+
Requires-Dist: argparse-from-file
|
16
|
+
Requires-Dist: pygithub
|
17
|
+
Requires-Dist: certifi
|
18
|
+
Requires-Dist: zstandard; python_version < "3.14"
|
19
|
+
|
1
20
|
## PYSTAND - Install Python Versions From The Python-Build-Standalone Project
|
2
21
|
[](https://pypi.org/project/pystand/)
|
3
22
|
[](https://aur.archlinux.org/packages/pystand/)
|
@@ -7,14 +26,14 @@ installation, and update of pre-built Python versions from the
|
|
7
26
|
[`python-build-standalone`][pbs] project. The following commands are
|
8
27
|
provided:
|
9
28
|
|
10
|
-
|Command |Description
|
11
|
-
|
12
|
-
|`install`|Install one or more versions from a python-build-standalone release
|
13
|
-
|`update` (or `upgrade`) |Update one, more, or all versions to another release
|
14
|
-
|`remove` (or `uninstall`) |Remove/uninstall one, more, or all versions
|
15
|
-
|`list` |List installed versions and show which have an update available
|
16
|
-
|`show` |Show versions available from a release
|
17
|
-
|`path` |Show path prefix to installed version base directory
|
29
|
+
|Command |Description |
|
30
|
+
|---------|--------------------------------------------------------------------|
|
31
|
+
|`install`|Install one or more versions from a python-build-standalone release.|
|
32
|
+
|`update` (or `upgrade`) |Update one, more, or all versions to another release.|
|
33
|
+
|`remove` (or `uninstall`) |Remove/uninstall one, more, or all versions.|
|
34
|
+
|`list` |List installed versions and show which have an update available.|
|
35
|
+
|`show` |Show versions available from a release.|
|
36
|
+
|`path` |Show path prefix to installed version base directory.|
|
18
37
|
|
19
38
|
By default, Python versions are sourced from the latest
|
20
39
|
`python-build-standalone` [release][pbs-rel] available (e.g.
|
@@ -113,7 +132,7 @@ Type `pystand` or `pystand -h` to view the usage summary:
|
|
113
132
|
usage: pystand [-h] [-D DISTRIBUTION] [-P PREFIX_DIR] [-C CACHE_DIR]
|
114
133
|
[-M CACHE_MINUTES] [--purge-days PURGE_DAYS]
|
115
134
|
[--github-access-token GITHUB_ACCESS_TOKEN] [--no-strip]
|
116
|
-
[-V]
|
135
|
+
[--cert {system,certifi,none}] [-V]
|
117
136
|
{install,update,upgrade,remove,uninstall,list,show,path,cache} ...
|
118
137
|
|
119
138
|
Command line tool to download, install, and update pre-built Python versions
|
@@ -129,22 +148,25 @@ options:
|
|
129
148
|
distributions.
|
130
149
|
-P, --prefix-dir PREFIX_DIR
|
131
150
|
specify prefix dir for storing versions. Default is
|
132
|
-
"$HOME/.local/share/pystand"
|
151
|
+
"$HOME/.local/share/pystand".
|
133
152
|
-C, --cache-dir CACHE_DIR
|
134
153
|
specify cache dir for downloads. Default is
|
135
|
-
"$HOME/.cache/pystand"
|
154
|
+
"$HOME/.cache/pystand".
|
136
155
|
-M, --cache-minutes CACHE_MINUTES
|
137
156
|
cache latest YYYYMMDD release tag fetch for this many
|
138
157
|
minutes, before rechecking for latest. Default is 60
|
139
|
-
minutes
|
158
|
+
minutes.
|
140
159
|
--purge-days PURGE_DAYS
|
141
160
|
cache YYYYMMDD release file lists and downloads for
|
142
161
|
this number of days after last version referencing
|
143
|
-
that release is removed. Default is 90 days
|
162
|
+
that release is removed. Default is 90 days.
|
144
163
|
--github-access-token GITHUB_ACCESS_TOKEN
|
145
164
|
optional Github access token. Can specify to reduce
|
146
165
|
rate limiting.
|
147
166
|
--no-strip do not strip downloaded binaries
|
167
|
+
--cert {system,certifi,none}
|
168
|
+
specify which SSL certificates to use for HTTPS
|
169
|
+
requests. Default="system".
|
148
170
|
-V, --version just show pystand version
|
149
171
|
|
150
172
|
Commands:
|
@@ -545,9 +567,8 @@ anything after on a line) are ignored. Type `pystand` to see all
|
|
545
567
|
supported options.
|
546
568
|
|
547
569
|
The global options: `--distribution`, `--prefix-dir`, `--cache-dir`,
|
548
|
-
`--cache-minutes`, `--purge-days`, `--github-access-token`,
|
549
|
-
`--
|
550
|
-
as defaults.
|
570
|
+
`--cache-minutes`, `--purge-days`, `--github-access-token`, `--no-strip`,
|
571
|
+
`--cert` are the only sensible candidates to consider setting as defaults.
|
551
572
|
|
552
573
|
## Github API Rate Limiting
|
553
574
|
|
@@ -562,6 +583,24 @@ either a Github "fine-grained" or "classic" token. Specify the token on
|
|
562
583
|
the command line with `--github-access-token`, or set that as a [default
|
563
584
|
option](#command-default-options).
|
564
585
|
|
586
|
+
## HTTPS Certificate Verification
|
587
|
+
|
588
|
+
A global option `--cert` is provided to specify which SSL certificates to use
|
589
|
+
for HTTPS requests. This is useful if you are running `pystand` in an
|
590
|
+
environment where the system certificates are not available, or you want to use
|
591
|
+
the bundled [`certifi`][certifi] certificates instead.
|
592
|
+
|
593
|
+
The available options are:
|
594
|
+
|
595
|
+
|Option |Description
|
596
|
+
|-------- |------------
|
597
|
+
|`system` |Use system certificates (as used normally by Python). This is the default.|
|
598
|
+
|`certifi`|Use the [`certifi`][certifi] package, i.e. use the certificates bundled within the application.|
|
599
|
+
|`none` |Perform unverified https requests (best to avoid using this).|
|
600
|
+
|
601
|
+
Specify the option on the command line with `--cert`, or set that as a [default
|
602
|
+
option](#command-default-options).
|
603
|
+
|
565
604
|
## Command Line Tab Completion
|
566
605
|
|
567
606
|
Command line shell [tab
|
@@ -581,7 +620,7 @@ either version 3 of the License, or any later version. This program is
|
|
581
620
|
distributed in the hope that it will be useful, but WITHOUT ANY
|
582
621
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
583
622
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License at
|
584
|
-
<
|
623
|
+
<https://opensource.org/license/gpl-3-0> for more details.
|
585
624
|
|
586
625
|
[pystand]: https://github.com/bulletmark/pystand
|
587
626
|
[pbs]: https://github.com/astral-sh/python-build-standalone
|
@@ -595,5 +634,6 @@ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License at
|
|
595
634
|
[hatch]: https://hatch.pypa.io/
|
596
635
|
[hatchpy]: https://hatch.pypa.io/latest/tutorials/python/manage/
|
597
636
|
[ryepy]: https://rye.astral.sh/guide/toolchains/#fetching-toolchains
|
637
|
+
[certifi]: https://pypi.org/project/certifi/
|
598
638
|
|
599
639
|
<!-- vim: se ai syn=markdown: -->
|
@@ -11,18 +11,20 @@ from __future__ import annotations
|
|
11
11
|
import os
|
12
12
|
import platform
|
13
13
|
import re
|
14
|
-
import shlex
|
15
14
|
import shutil
|
15
|
+
import ssl
|
16
16
|
import sys
|
17
17
|
import time
|
18
|
-
from argparse import ArgumentParser, Namespace
|
19
18
|
from collections import defaultdict
|
19
|
+
from collections.abc import Iterable, Iterator
|
20
20
|
from datetime import date, datetime
|
21
21
|
from pathlib import Path
|
22
|
-
from typing import Any
|
22
|
+
from typing import Any
|
23
|
+
from urllib.request import urlopen
|
23
24
|
|
24
25
|
import argcomplete
|
25
26
|
import platformdirs
|
27
|
+
from argparse_from_file import ArgumentParser, Namespace # type: ignore
|
26
28
|
from packaging.version import parse as parse_version
|
27
29
|
|
28
30
|
REPO = 'python-build-standalone'
|
@@ -35,7 +37,6 @@ LATEST_RELEASE_TAG = f'{GITHUB_SITE}/releases/latest'
|
|
35
37
|
SAMPL_RELEASE = '20240415'
|
36
38
|
|
37
39
|
PROG = Path(__file__).stem
|
38
|
-
CNFFILE = platformdirs.user_config_path(f'{PROG}-flags.conf')
|
39
40
|
|
40
41
|
# Default distributions for various platforms
|
41
42
|
DISTRIBUTIONS = {
|
@@ -45,10 +46,13 @@ DISTRIBUTIONS = {
|
|
45
46
|
('Linux', 'armv8l'): 'armv7-unknown-linux-gnueabihf-install_only_stripped',
|
46
47
|
('Darwin', 'x86_64'): 'x86_64-apple-darwin-install_only_stripped',
|
47
48
|
('Darwin', 'aarch64'): 'aarch64-apple-darwin-install_only_stripped',
|
49
|
+
('Darwin', 'arm64'): 'aarch64-apple-darwin-install_only_stripped',
|
48
50
|
('Windows', 'x86_64'): 'x86_64-pc-windows-msvc-shared-install_only_stripped',
|
49
51
|
('Windows', 'i686'): 'i686-pc-windows-msvc-shared-install_only_stripped',
|
50
52
|
}
|
51
53
|
|
54
|
+
CERTS = ('system', 'certifi', 'none')
|
55
|
+
|
52
56
|
|
53
57
|
def is_admin() -> bool:
|
54
58
|
"Check if we are running as root"
|
@@ -77,7 +81,7 @@ def fmt(version, release) -> str:
|
|
77
81
|
return f'{version} @ {release}'
|
78
82
|
|
79
83
|
|
80
|
-
def get_json(file: Path) -> dict:
|
84
|
+
def get_json(file: Path) -> dict[str, Any]:
|
81
85
|
from json import load
|
82
86
|
|
83
87
|
'Get JSON data from given file'
|
@@ -90,7 +94,7 @@ def get_json(file: Path) -> dict:
|
|
90
94
|
return {}
|
91
95
|
|
92
96
|
|
93
|
-
def set_json(file: Path, data: dict) -> str | None:
|
97
|
+
def set_json(file: Path, data: dict[str, Any]) -> str | None:
|
94
98
|
"Set JSON data to given file"
|
95
99
|
from json import dump
|
96
100
|
|
@@ -138,23 +142,30 @@ def rm_path(path: Path) -> None:
|
|
138
142
|
path.unlink()
|
139
143
|
|
140
144
|
|
141
|
-
def
|
142
|
-
"
|
143
|
-
|
145
|
+
def register_zst() -> None:
|
146
|
+
"Register custom zstandard unpacker"
|
147
|
+
# Python 3.14+ has built-in support for zstandard so only register custom
|
148
|
+
# handler for earlier versions
|
149
|
+
if sys.version_info < (3, 14):
|
150
|
+
|
151
|
+
def unpack_zst(filename: str, extract_dir: str) -> None:
|
152
|
+
"Unpack a zstandard compressed tar"
|
153
|
+
import tarfile
|
144
154
|
|
145
|
-
|
155
|
+
import zstandard
|
146
156
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
157
|
+
with open(filename, 'rb') as compressed:
|
158
|
+
dctx = zstandard.ZstdDecompressor()
|
159
|
+
with dctx.stream_reader(compressed) as reader:
|
160
|
+
with tarfile.open(fileobj=reader, mode='r|') as tar:
|
161
|
+
tar.extractall(path=extract_dir)
|
162
|
+
|
163
|
+
shutil.register_unpack_format('zst', ['.zst'], unpack_zst)
|
152
164
|
|
153
165
|
|
154
166
|
def fetch(args: Namespace, release: str, url: str, tdir: Path) -> str | None:
|
155
167
|
"Fetch and unpack a release file"
|
156
168
|
from urllib.parse import unquote, urlparse
|
157
|
-
from urllib.request import urlretrieve
|
158
169
|
|
159
170
|
error = None
|
160
171
|
tmpdir = tdir.with_name(f'{tdir.name}-tmp')
|
@@ -168,7 +179,8 @@ def fetch(args: Namespace, release: str, url: str, tdir: Path) -> str | None:
|
|
168
179
|
|
169
180
|
if not cache_file.exists():
|
170
181
|
try:
|
171
|
-
|
182
|
+
with urlopen(url, context=args._cert) as urlp, cache_file.open('wb') as fp:
|
183
|
+
shutil.copyfileobj(urlp, fp)
|
172
184
|
except Exception as e:
|
173
185
|
error = f'Failed to fetch "{url}": {e}'
|
174
186
|
|
@@ -176,7 +188,7 @@ def fetch(args: Namespace, release: str, url: str, tdir: Path) -> str | None:
|
|
176
188
|
rm_path(cache_file)
|
177
189
|
else:
|
178
190
|
if filename.endswith('.zst'):
|
179
|
-
|
191
|
+
register_zst()
|
180
192
|
|
181
193
|
try:
|
182
194
|
shutil.unpack_archive(cache_file, tmpdir)
|
@@ -306,13 +318,12 @@ def check_release_tag(release: str) -> str | None:
|
|
306
318
|
# Note we use a simple direct URL fetch to get the latest tag info
|
307
319
|
# because it is much faster than using the GitHub API, and has no
|
308
320
|
# rate-limits.
|
309
|
-
def fetch_tags() -> Iterator[tuple[str, str]]:
|
321
|
+
def fetch_tags(args: Namespace) -> Iterator[tuple[str, str]]:
|
310
322
|
"Fetch the latest release tags from the GitHub release atom feed"
|
311
323
|
import xml.etree.ElementTree as et
|
312
|
-
from urllib.request import urlopen
|
313
324
|
|
314
325
|
try:
|
315
|
-
with urlopen(LATEST_RELEASES) as url:
|
326
|
+
with urlopen(LATEST_RELEASES, context=args._cert) as url:
|
316
327
|
data = et.parse(url).getroot()
|
317
328
|
except Exception:
|
318
329
|
sys.exit('Failed to fetch latest YYYYMMDD release atom file.')
|
@@ -325,12 +336,10 @@ def fetch_tags() -> Iterator[tuple[str, str]]:
|
|
325
336
|
yield tl, dt
|
326
337
|
|
327
338
|
|
328
|
-
def fetch_tag_latest() -> str:
|
339
|
+
def fetch_tag_latest(args: Namespace) -> str:
|
329
340
|
"Fetch the latest release tag from the GitHub"
|
330
|
-
from urllib.request import urlopen
|
331
|
-
|
332
341
|
try:
|
333
|
-
with urlopen(LATEST_RELEASE_TAG) as url:
|
342
|
+
with urlopen(LATEST_RELEASE_TAG, context=args._cert) as url:
|
334
343
|
data = url.geturl()
|
335
344
|
except Exception:
|
336
345
|
sys.exit('Failed to fetch latest YYYYMMDD release tag.')
|
@@ -351,14 +360,14 @@ def get_release_tag(args: Namespace) -> str:
|
|
351
360
|
if time.time() < (stat.st_mtime + int(args.cache_minutes * 60)):
|
352
361
|
return args._latest_release.read_text().strip()
|
353
362
|
|
354
|
-
if not (tag := fetch_tag_latest()):
|
363
|
+
if not (tag := fetch_tag_latest(args)):
|
355
364
|
sys.exit('Latest YYYYMMDD release tag timestamp file is unavailable.')
|
356
365
|
|
357
366
|
args._latest_release.write_text(tag + '\n')
|
358
367
|
return tag
|
359
368
|
|
360
369
|
|
361
|
-
def add_file(files: dict, tag: str, name: str, url: str) -> None:
|
370
|
+
def add_file(files: dict[str, Any], tag: str, name: str, url: str) -> None:
|
362
371
|
"Extract the implementation, version, and architecture from a filename"
|
363
372
|
if name.endswith('.tar.zst'):
|
364
373
|
name = name[:-8]
|
@@ -386,7 +395,7 @@ def add_file(files: dict, tag: str, name: str, url: str) -> None:
|
|
386
395
|
vers[ver][arch] = url
|
387
396
|
|
388
397
|
|
389
|
-
def get_release_files(args, tag
|
398
|
+
def get_release_files(args, tag) -> dict[str, Any]:
|
390
399
|
"Return the release files for the given tag"
|
391
400
|
# Look for tag data in our release cache
|
392
401
|
jfile = args._releases / tag
|
@@ -414,7 +423,7 @@ def get_release_files(args, tag, implementation: str | None = None) -> dict:
|
|
414
423
|
if error := set_json(jfile, files):
|
415
424
|
sys.exit(f'Failed to write release {tag} file {jfile}: {error}')
|
416
425
|
|
417
|
-
return files.get(
|
426
|
+
return files.get(args._implementation, {})
|
418
427
|
|
419
428
|
|
420
429
|
def update_version_symlinks(args: Namespace) -> None:
|
@@ -499,7 +508,7 @@ def purge_unused_releases(args: Namespace) -> None:
|
|
499
508
|
def show_list(args: Namespace) -> None:
|
500
509
|
"Show a list of available releases"
|
501
510
|
latest = parse_version(get_release_tag(args))
|
502
|
-
releases = {r: d for r, d in fetch_tags()}
|
511
|
+
releases = {r: d for r, d in fetch_tags(args)}
|
503
512
|
cached = set(p.name for p in args._releases.iterdir())
|
504
513
|
for release in sorted(cached.union(releases)):
|
505
514
|
if args.re_match and not re.search(args.re_match, release):
|
@@ -578,7 +587,7 @@ def strip_binaries(vdir: Path, distribution: str) -> bool:
|
|
578
587
|
|
579
588
|
|
580
589
|
def install(
|
581
|
-
args: Namespace, vdir: Path, release: str, distribution: str, files: dict
|
590
|
+
args: Namespace, vdir: Path, release: str, distribution: str, files: dict[str, Any]
|
582
591
|
) -> str | None:
|
583
592
|
"Install a version"
|
584
593
|
version = vdir.name
|
@@ -640,6 +649,21 @@ def show_cache_size(path: Path, args: Namespace) -> None:
|
|
640
649
|
print(f'{size_str}\tTOTAL')
|
641
650
|
|
642
651
|
|
652
|
+
def create_cert(option: str) -> ssl.SSLContext | None:
|
653
|
+
"Create an SSL context for HTTPS connections based on the specified certificate store"
|
654
|
+
|
655
|
+
if not option or option == 'system':
|
656
|
+
return None
|
657
|
+
|
658
|
+
if option == 'certifi':
|
659
|
+
import certifi
|
660
|
+
|
661
|
+
return ssl.create_default_context(cafile=certifi.where())
|
662
|
+
|
663
|
+
assert option == 'none'
|
664
|
+
return ssl._create_unverified_context()
|
665
|
+
|
666
|
+
|
643
667
|
def main() -> str | None:
|
644
668
|
"Main code"
|
645
669
|
distro_default = DISTRIBUTIONS.get((platform.system(), platform.machine()))
|
@@ -653,8 +677,7 @@ def main() -> str | None:
|
|
653
677
|
opt = ArgumentParser(
|
654
678
|
description=__doc__,
|
655
679
|
epilog='Some commands offer aliases as shown in parentheses above. '
|
656
|
-
'Note you can set default starting global options in '
|
657
|
-
f'{CNFFILE}.',
|
680
|
+
'Note you can set default starting global options in #FROM_FILE_PATH#',
|
658
681
|
)
|
659
682
|
|
660
683
|
# Set up main/global arguments
|
@@ -668,13 +691,13 @@ def main() -> str | None:
|
|
668
691
|
'-P',
|
669
692
|
'--prefix-dir',
|
670
693
|
default=prefix_dir,
|
671
|
-
help='specify prefix dir for storing versions. Default is "%(default)s"',
|
694
|
+
help='specify prefix dir for storing versions. Default is "%(default)s".',
|
672
695
|
)
|
673
696
|
opt.add_argument(
|
674
697
|
'-C',
|
675
698
|
'--cache-dir',
|
676
699
|
default=str(cache_dir),
|
677
|
-
help='specify cache dir for downloads. Default is "%(default)s"',
|
700
|
+
help='specify cache dir for downloads. Default is "%(default)s".',
|
678
701
|
)
|
679
702
|
opt.add_argument(
|
680
703
|
'-M',
|
@@ -683,7 +706,7 @@ def main() -> str | None:
|
|
683
706
|
type=float,
|
684
707
|
help='cache latest YYYYMMDD release tag fetch for this '
|
685
708
|
'many minutes, before rechecking for latest. '
|
686
|
-
'Default is %(default)d minutes',
|
709
|
+
'Default is %(default)d minutes.',
|
687
710
|
)
|
688
711
|
opt.add_argument(
|
689
712
|
'--purge-days',
|
@@ -691,7 +714,7 @@ def main() -> str | None:
|
|
691
714
|
type=int,
|
692
715
|
help='cache YYYYMMDD release file lists and downloads for '
|
693
716
|
'this number of days after last version referencing that '
|
694
|
-
'release is removed. Default is %(default)d days',
|
717
|
+
'release is removed. Default is %(default)d days.',
|
695
718
|
)
|
696
719
|
opt.add_argument(
|
697
720
|
'--github-access-token',
|
@@ -700,6 +723,11 @@ def main() -> str | None:
|
|
700
723
|
opt.add_argument(
|
701
724
|
'--no-strip', action='store_true', help='do not strip downloaded binaries'
|
702
725
|
)
|
726
|
+
opt.add_argument(
|
727
|
+
'--cert',
|
728
|
+
choices=CERTS,
|
729
|
+
help=f'specify which SSL certificates to use for HTTPS requests. Default="{CERTS[0]}".',
|
730
|
+
)
|
703
731
|
opt.add_argument(
|
704
732
|
'-V', '--version', action='store_true', help=f'just show {PROG} version'
|
705
733
|
)
|
@@ -733,18 +761,7 @@ def main() -> str | None:
|
|
733
761
|
|
734
762
|
# Command arguments are now defined, so we can set up argcomplete
|
735
763
|
argcomplete.autocomplete(opt)
|
736
|
-
|
737
|
-
# Merge in default args from user config file. Then parse the
|
738
|
-
# command line.
|
739
|
-
cnffile = CNFFILE.expanduser()
|
740
|
-
if cnffile.is_file():
|
741
|
-
with cnffile.open() as fp:
|
742
|
-
lines = [re.sub(r'#.*$', '', line).strip() for line in fp]
|
743
|
-
cnflines = ' '.join(lines).strip()
|
744
|
-
else:
|
745
|
-
cnflines = ''
|
746
|
-
|
747
|
-
args = opt.parse_args(shlex.split(cnflines) + sys.argv[1:])
|
764
|
+
args = opt.parse_args()
|
748
765
|
|
749
766
|
if 'func' not in args:
|
750
767
|
if args.version:
|
@@ -765,6 +782,7 @@ def main() -> str | None:
|
|
765
782
|
prefix_dir = Path(args.prefix_dir).expanduser().resolve()
|
766
783
|
cache_dir = Path(args.cache_dir).expanduser().resolve()
|
767
784
|
|
785
|
+
args._implementation = 'cpython' # at the moment, only support CPython
|
768
786
|
args._distribution = distribution
|
769
787
|
args._data = f'{PROG}.json'
|
770
788
|
|
@@ -776,6 +794,7 @@ def main() -> str | None:
|
|
776
794
|
args._releases = cache_dir / 'releases'
|
777
795
|
args._releases.mkdir(parents=True, exist_ok=True)
|
778
796
|
args._latest_release = cache_dir / 'latest_release'
|
797
|
+
args._cert = create_cert(args.cert)
|
779
798
|
|
780
799
|
result = args.func(args)
|
781
800
|
purge_unused_releases(args)
|
@@ -815,7 +834,7 @@ class install_:
|
|
815
834
|
@staticmethod
|
816
835
|
def run(args: Namespace) -> str | None:
|
817
836
|
release = get_release_tag(args)
|
818
|
-
files = get_release_files(args, release
|
837
|
+
files = get_release_files(args, release)
|
819
838
|
if not files:
|
820
839
|
return f'Release "{release}" not found, or has no compatible files.'
|
821
840
|
|
@@ -874,7 +893,7 @@ class update_:
|
|
874
893
|
@staticmethod
|
875
894
|
def run(args: Namespace) -> str | None:
|
876
895
|
release_target = get_release_tag(args)
|
877
|
-
files = get_release_files(args, release_target
|
896
|
+
files = get_release_files(args, release_target)
|
878
897
|
if not files:
|
879
898
|
return f'Release "{release_target}" not found.'
|
880
899
|
|
@@ -991,7 +1010,7 @@ class list_:
|
|
991
1010
|
@staticmethod
|
992
1011
|
def run(args: Namespace) -> str | None:
|
993
1012
|
release_target = get_release_tag(args)
|
994
|
-
files = get_release_files(args, release_target
|
1013
|
+
files = get_release_files(args, release_target)
|
995
1014
|
if not files:
|
996
1015
|
return f'Release "{release_target}" not found.'
|
997
1016
|
|
@@ -1089,7 +1108,7 @@ class show_:
|
|
1089
1108
|
return None
|
1090
1109
|
|
1091
1110
|
release = get_release_tag(args)
|
1092
|
-
files = get_release_files(args, release
|
1111
|
+
files = get_release_files(args, release)
|
1093
1112
|
if not files:
|
1094
1113
|
return f'Error: release "{release}" not found.'
|
1095
1114
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|