pystand 2.5__tar.gz → 2.7__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.5/pystand.egg-info → pystand-2.7}/PKG-INFO +7 -5
- {pystand-2.5 → pystand-2.7}/README.md +6 -4
- {pystand-2.5 → pystand-2.7/pystand.egg-info}/PKG-INFO +7 -5
- {pystand-2.5 → pystand-2.7}/pystand.py +90 -45
- {pystand-2.5 → pystand-2.7}/.flake8 +0 -0
- {pystand-2.5 → pystand-2.7}/.gitignore +0 -0
- {pystand-2.5 → pystand-2.7}/Makefile +0 -0
- {pystand-2.5 → pystand-2.7}/pyproject.toml +0 -0
- {pystand-2.5 → pystand-2.7}/pystand.egg-info/SOURCES.txt +0 -0
- {pystand-2.5 → pystand-2.7}/pystand.egg-info/dependency_links.txt +0 -0
- {pystand-2.5 → pystand-2.7}/pystand.egg-info/entry_points.txt +0 -0
- {pystand-2.5 → pystand-2.7}/pystand.egg-info/requires.txt +0 -0
- {pystand-2.5 → pystand-2.7}/pystand.egg-info/top_level.txt +0 -0
- {pystand-2.5 → pystand-2.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pystand
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.7
|
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: GPLv3
|
@@ -141,7 +141,7 @@ options:
|
|
141
141
|
-h, --help show this help message and exit
|
142
142
|
-D DISTRIBUTION, --distribution DISTRIBUTION
|
143
143
|
python-build-standalone distribution. Default is
|
144
|
-
"
|
144
|
+
"x86_64_v3-unknown-linux-gnu-install_only_stripped for
|
145
145
|
this host.
|
146
146
|
-P PREFIX_DIR, --prefix-dir PREFIX_DIR
|
147
147
|
specify prefix dir for storing versions. Default is
|
@@ -160,7 +160,7 @@ options:
|
|
160
160
|
--github-access-token GITHUB_ACCESS_TOKEN
|
161
161
|
optional Github access token. Can specify to reduce
|
162
162
|
rate limiting.
|
163
|
-
--no-strip do strip downloaded binaries
|
163
|
+
--no-strip do not strip downloaded binaries
|
164
164
|
-V, --version just show pystand version
|
165
165
|
|
166
166
|
Commands:
|
@@ -270,9 +270,10 @@ options:
|
|
270
270
|
### Command `show`
|
271
271
|
|
272
272
|
```
|
273
|
-
usage: pystand show [-h] [-r RELEASE] [-a] [re_match]
|
273
|
+
usage: pystand show [-h] [-l | -r RELEASE] [-a] [re_match]
|
274
274
|
|
275
|
-
Show versions available from a release.
|
275
|
+
Show versions available from a release. View available releases and their
|
276
|
+
distributions at https://github.com/indygreg/python-build-standalone/releases.
|
276
277
|
|
277
278
|
positional arguments:
|
278
279
|
re_match show only versions+distributions matching this regular
|
@@ -280,6 +281,7 @@ positional arguments:
|
|
280
281
|
|
281
282
|
options:
|
282
283
|
-h, --help show this help message and exit
|
284
|
+
-l, --list just list recent releases
|
283
285
|
-r RELEASE, --release RELEASE
|
284
286
|
python-build-standalone YYYYMMDD release to show (e.g.
|
285
287
|
20240415), default is latest release
|
@@ -124,7 +124,7 @@ options:
|
|
124
124
|
-h, --help show this help message and exit
|
125
125
|
-D DISTRIBUTION, --distribution DISTRIBUTION
|
126
126
|
python-build-standalone distribution. Default is
|
127
|
-
"
|
127
|
+
"x86_64_v3-unknown-linux-gnu-install_only_stripped for
|
128
128
|
this host.
|
129
129
|
-P PREFIX_DIR, --prefix-dir PREFIX_DIR
|
130
130
|
specify prefix dir for storing versions. Default is
|
@@ -143,7 +143,7 @@ options:
|
|
143
143
|
--github-access-token GITHUB_ACCESS_TOKEN
|
144
144
|
optional Github access token. Can specify to reduce
|
145
145
|
rate limiting.
|
146
|
-
--no-strip do strip downloaded binaries
|
146
|
+
--no-strip do not strip downloaded binaries
|
147
147
|
-V, --version just show pystand version
|
148
148
|
|
149
149
|
Commands:
|
@@ -253,9 +253,10 @@ options:
|
|
253
253
|
### Command `show`
|
254
254
|
|
255
255
|
```
|
256
|
-
usage: pystand show [-h] [-r RELEASE] [-a] [re_match]
|
256
|
+
usage: pystand show [-h] [-l | -r RELEASE] [-a] [re_match]
|
257
257
|
|
258
|
-
Show versions available from a release.
|
258
|
+
Show versions available from a release. View available releases and their
|
259
|
+
distributions at https://github.com/indygreg/python-build-standalone/releases.
|
259
260
|
|
260
261
|
positional arguments:
|
261
262
|
re_match show only versions+distributions matching this regular
|
@@ -263,6 +264,7 @@ positional arguments:
|
|
263
264
|
|
264
265
|
options:
|
265
266
|
-h, --help show this help message and exit
|
267
|
+
-l, --list just list recent releases
|
266
268
|
-r RELEASE, --release RELEASE
|
267
269
|
python-build-standalone YYYYMMDD release to show (e.g.
|
268
270
|
20240415), default is latest release
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pystand
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.7
|
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: GPLv3
|
@@ -141,7 +141,7 @@ options:
|
|
141
141
|
-h, --help show this help message and exit
|
142
142
|
-D DISTRIBUTION, --distribution DISTRIBUTION
|
143
143
|
python-build-standalone distribution. Default is
|
144
|
-
"
|
144
|
+
"x86_64_v3-unknown-linux-gnu-install_only_stripped for
|
145
145
|
this host.
|
146
146
|
-P PREFIX_DIR, --prefix-dir PREFIX_DIR
|
147
147
|
specify prefix dir for storing versions. Default is
|
@@ -160,7 +160,7 @@ options:
|
|
160
160
|
--github-access-token GITHUB_ACCESS_TOKEN
|
161
161
|
optional Github access token. Can specify to reduce
|
162
162
|
rate limiting.
|
163
|
-
--no-strip do strip downloaded binaries
|
163
|
+
--no-strip do not strip downloaded binaries
|
164
164
|
-V, --version just show pystand version
|
165
165
|
|
166
166
|
Commands:
|
@@ -270,9 +270,10 @@ options:
|
|
270
270
|
### Command `show`
|
271
271
|
|
272
272
|
```
|
273
|
-
usage: pystand show [-h] [-r RELEASE] [-a] [re_match]
|
273
|
+
usage: pystand show [-h] [-l | -r RELEASE] [-a] [re_match]
|
274
274
|
|
275
|
-
Show versions available from a release.
|
275
|
+
Show versions available from a release. View available releases and their
|
276
|
+
distributions at https://github.com/indygreg/python-build-standalone/releases.
|
276
277
|
|
277
278
|
positional arguments:
|
278
279
|
re_match show only versions+distributions matching this regular
|
@@ -280,6 +281,7 @@ positional arguments:
|
|
280
281
|
|
281
282
|
options:
|
282
283
|
-h, --help show this help message and exit
|
284
|
+
-l, --list just list recent releases
|
283
285
|
-r RELEASE, --release RELEASE
|
284
286
|
python-build-standalone YYYYMMDD release to show (e.g.
|
285
287
|
20240415), default is latest release
|
@@ -19,9 +19,9 @@ import tarfile
|
|
19
19
|
import time
|
20
20
|
import urllib.parse
|
21
21
|
import urllib.request
|
22
|
-
from argparse import ArgumentParser, Namespace
|
22
|
+
from argparse import ArgumentParser, Namespace, SUPPRESS
|
23
23
|
from collections import defaultdict
|
24
|
-
from datetime import date
|
24
|
+
from datetime import datetime, date, timedelta
|
25
25
|
from pathlib import Path
|
26
26
|
from typing import Any, Iterable, Iterator
|
27
27
|
|
@@ -30,11 +30,10 @@ import platformdirs
|
|
30
30
|
import zstandard
|
31
31
|
from packaging.version import parse as parse_version
|
32
32
|
|
33
|
-
REPO_OWNER = 'indygreg'
|
34
33
|
REPO = 'python-build-standalone'
|
35
|
-
GITHUB_REPO = f'
|
36
|
-
|
37
|
-
|
34
|
+
GITHUB_REPO = f'indygreg/{REPO}'
|
35
|
+
GITHUB_SITE = f'https://github.com/{GITHUB_REPO}'
|
36
|
+
LATEST_RELEASE = f'{GITHUB_SITE}/releases.atom'
|
38
37
|
|
39
38
|
# Sample release tag for documentation/usage examples
|
40
39
|
SAMPL_RELEASE = '20240415'
|
@@ -44,14 +43,15 @@ CNFFILE = platformdirs.user_config_path(f'{PROG}-flags.conf')
|
|
44
43
|
|
45
44
|
# Default distributions for various platforms
|
46
45
|
DISTRIBUTIONS = {
|
47
|
-
('Linux', 'x86_64'): '
|
46
|
+
('Linux', 'x86_64'): 'x86_64_v3-unknown-linux-gnu-install_only_stripped',
|
48
47
|
('Linux', 'aarch64'): 'aarch64-unknown-linux-gnu-install_only_stripped',
|
49
48
|
('Linux', 'armv7l'): 'armv7-unknown-linux-gnueabihf-install_only_stripped',
|
50
49
|
('Linux', 'armv8l'): 'armv7-unknown-linux-gnueabihf-install_only_stripped',
|
51
50
|
('Darwin', 'x86_64'): 'x86_64-apple-darwin-install_only_stripped',
|
52
51
|
('Darwin', 'aarch64'): 'aarch64-apple-darwin-install_only_stripped',
|
53
|
-
('Windows', 'x86_64'):
|
54
|
-
|
52
|
+
('Windows', 'x86_64'):
|
53
|
+
'x86_64-pc-windows-msvc-shared-install_only_stripped',
|
54
|
+
('Windows', 'i686'): 'i686-pc-windows-msvc-shared-install_only_stripped',
|
55
55
|
}
|
56
56
|
|
57
57
|
def is_admin() -> bool:
|
@@ -274,6 +274,34 @@ def check_release_tag(release: str) -> str | None:
|
|
274
274
|
|
275
275
|
return None
|
276
276
|
|
277
|
+
# Note we use a simple direct URL fetch to get the latest tag info
|
278
|
+
# because it is much faster than using the GitHub API, and has no
|
279
|
+
# rate-limits.
|
280
|
+
def fetch_tags() -> Iterator[tuple[str, str]]:
|
281
|
+
'Fetch the latest release tag from the GitHub release atom feed'
|
282
|
+
import xml.etree.ElementTree as et
|
283
|
+
try:
|
284
|
+
with urllib.request.urlopen(LATEST_RELEASE) as url:
|
285
|
+
data = et.parse(url).getroot()
|
286
|
+
except Exception:
|
287
|
+
sys.exit('Failed to fetch latest YYYYMMDD release atom file.')
|
288
|
+
|
289
|
+
for child in data.iter():
|
290
|
+
for entry in child.findall('{http://www.w3.org/2005/Atom}entry'):
|
291
|
+
tl = entry.findtext('{http://www.w3.org/2005/Atom}title')
|
292
|
+
dt = entry.findtext('{http://www.w3.org/2005/Atom}updated')
|
293
|
+
if tl and dt:
|
294
|
+
yield tl, dt
|
295
|
+
|
296
|
+
def fetch_tag_latest(args: Namespace) -> str:
|
297
|
+
now = datetime.now().astimezone()
|
298
|
+
for title, datestr in fetch_tags():
|
299
|
+
timestamp = datetime.fromisoformat(datestr)
|
300
|
+
if now - timestamp >= args._min_release_time:
|
301
|
+
return title
|
302
|
+
|
303
|
+
return ''
|
304
|
+
|
277
305
|
def get_release_tag(args: Namespace) -> str:
|
278
306
|
'Return the release tag, or latest if not specified'
|
279
307
|
if release := args.release:
|
@@ -287,19 +315,8 @@ def get_release_tag(args: Namespace) -> str:
|
|
287
315
|
if time.time() < (stat.st_mtime + int(args.cache_minutes * 60)):
|
288
316
|
return args._latest_release.read_text().strip()
|
289
317
|
|
290
|
-
|
291
|
-
|
292
|
-
# release tag.
|
293
|
-
try:
|
294
|
-
with urllib.request.urlopen(LATEST_RELEASE_URL) as url:
|
295
|
-
data = json.load(url)
|
296
|
-
except Exception:
|
297
|
-
sys.exit('Failed to fetch latest YYYYMMDD release tag.')
|
298
|
-
|
299
|
-
tag = data.get('tag')
|
300
|
-
|
301
|
-
if not tag:
|
302
|
-
sys.exit('Latest YYYYMMDD release tag timestamp file is corrupted.')
|
318
|
+
if not (tag := fetch_tag_latest(args)):
|
319
|
+
sys.exit('Latest YYYYMMDD release tag timestamp file is unavailable.')
|
303
320
|
|
304
321
|
args._latest_release.write_text(tag + '\n')
|
305
322
|
return tag
|
@@ -414,28 +431,28 @@ def update_version_symlinks(args: Namespace) -> None:
|
|
414
431
|
|
415
432
|
def purge_unused_releases(args: Namespace) -> None:
|
416
433
|
'Purge old releases that are no longer needed and have expired'
|
417
|
-
|
418
|
-
keep =
|
434
|
+
# Want to keep releases for versions that we currently have installed
|
435
|
+
keep = {r for v in iter_versions(args)
|
436
|
+
if (r := get_json(v / args._data).get('release'))}
|
437
|
+
|
438
|
+
# Add current release to keep list (even if not currently installed)
|
419
439
|
if args._latest_release.exists():
|
420
440
|
keep.add(args._latest_release.read_text().strip())
|
421
441
|
|
422
|
-
|
423
|
-
if (release := get_json(version / args._data).get('release')):
|
424
|
-
keep.add(release)
|
425
|
-
|
442
|
+
# Purge any release lists that are no longer used and have expired
|
426
443
|
now_secs = time.time()
|
427
444
|
end_secs = args.purge_days * 86400
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
keep.add(release)
|
445
|
+
for path in args._releases.iterdir():
|
446
|
+
if path.name not in keep:
|
447
|
+
if (path.stat().st_mtime + end_secs) < now_secs:
|
448
|
+
path.unlink()
|
449
|
+
else:
|
450
|
+
keep.add(path.name)
|
435
451
|
|
436
|
-
|
437
|
-
for
|
438
|
-
|
452
|
+
# Purge any downloads for releases that have expired
|
453
|
+
for path in args._downloads.iterdir():
|
454
|
+
if path.name not in keep:
|
455
|
+
rm_path(path)
|
439
456
|
|
440
457
|
class COMMAND:
|
441
458
|
'Base class for all commands'
|
@@ -540,8 +557,7 @@ def main() -> str | None:
|
|
540
557
|
# Set up main/global arguments
|
541
558
|
opt.add_argument('-D', '--distribution',
|
542
559
|
help=f'{REPO} distribution. '
|
543
|
-
f'Default is "{distro_help}
|
544
|
-
'for this host.')
|
560
|
+
f'Default is "{distro_help} for this host.')
|
545
561
|
opt.add_argument('-P', '--prefix-dir', default=prefix_dir,
|
546
562
|
help='specify prefix dir for storing '
|
547
563
|
'versions. Default is "%(default)s"')
|
@@ -560,9 +576,11 @@ def main() -> str | None:
|
|
560
576
|
help='optional Github access token. Can specify to reduce '
|
561
577
|
'rate limiting.')
|
562
578
|
opt.add_argument('--no-strip', action='store_true',
|
563
|
-
help='do strip downloaded binaries')
|
579
|
+
help='do not strip downloaded binaries')
|
564
580
|
opt.add_argument('-V', '--version', action='store_true',
|
565
581
|
help=f'just show {PROG} version')
|
582
|
+
opt.add_argument('--min-release-hours', default=6, type=int,
|
583
|
+
help=SUPPRESS)
|
566
584
|
cmd = opt.add_subparsers(title='Commands', dest='cmdname')
|
567
585
|
|
568
586
|
# Add each command ..
|
@@ -631,6 +649,7 @@ def main() -> str | None:
|
|
631
649
|
args._releases = cache_dir / 'releases'
|
632
650
|
args._releases.mkdir(parents=True, exist_ok=True)
|
633
651
|
args._latest_release = cache_dir / 'latest_release'
|
652
|
+
args._min_release_time = timedelta(hours=args.min_release_hours)
|
634
653
|
|
635
654
|
result = args.func(args)
|
636
655
|
purge_unused_releases(args)
|
@@ -849,12 +868,21 @@ class _list(COMMAND):
|
|
849
868
|
|
850
869
|
@COMMAND.add
|
851
870
|
class _show(COMMAND):
|
852
|
-
|
871
|
+
doc = f'''
|
872
|
+
Show versions available from a release.
|
873
|
+
|
874
|
+
View available releases and their distributions at
|
875
|
+
{GITHUB_SITE}/releases.
|
876
|
+
'''
|
877
|
+
|
853
878
|
@staticmethod
|
854
879
|
def init(parser: ArgumentParser) -> None:
|
855
|
-
parser.
|
856
|
-
|
857
|
-
|
880
|
+
group = parser.add_mutually_exclusive_group()
|
881
|
+
group.add_argument('-l', '--list', action='store_true',
|
882
|
+
help='just list recent releases')
|
883
|
+
group.add_argument('-r', '--release',
|
884
|
+
help=f'{REPO} YYYYMMDD release to show (e.g. '
|
885
|
+
f'{SAMPL_RELEASE}), default is latest release')
|
858
886
|
parser.add_argument('-a', '--all', action='store_true',
|
859
887
|
help='show all available distributions for '
|
860
888
|
'each version from the release')
|
@@ -864,6 +892,23 @@ class _show(COMMAND):
|
|
864
892
|
|
865
893
|
@staticmethod
|
866
894
|
def run(args: Namespace) -> None:
|
895
|
+
if args.all and args.list:
|
896
|
+
args.parser.error('Can not specify --all with --list.')
|
897
|
+
|
898
|
+
if args.list:
|
899
|
+
now = datetime.now().astimezone()
|
900
|
+
for title, datestr in fetch_tags():
|
901
|
+
if args.re_match and not re.search(args.re_match, title):
|
902
|
+
continue
|
903
|
+
|
904
|
+
tdiff = now - datetime.fromisoformat(datestr)
|
905
|
+
if tdiff < args._min_release_time:
|
906
|
+
print(title, '(pending)')
|
907
|
+
else:
|
908
|
+
print(title)
|
909
|
+
|
910
|
+
return
|
911
|
+
|
867
912
|
release = get_release_tag(args)
|
868
913
|
files = get_release_files(args, release, 'cpython')
|
869
914
|
if not files:
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|