sbo-create 2.3.0__tar.gz → 2.3.2__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.
- {sbo_create-2.3.0 → sbo_create-2.3.2}/PKG-INFO +1 -1
- {sbo_create-2.3.0 → sbo_create-2.3.2}/pyproject.toml +5 -1
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/__metadata__.py +1 -2
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/handlers/bump.py +1 -2
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/handlers/download.py +2 -2
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/handlers/files.py +9 -2
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/handlers/fix.py +19 -11
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/handlers/git.py +9 -2
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/handlers/misc.py +31 -8
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/handlers/validate.py +44 -8
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/models.py +1 -0
- {sbo_create-2.3.0 → sbo_create-2.3.2}/LICENSE +0 -0
- {sbo_create-2.3.0 → sbo_create-2.3.2}/README.md +0 -0
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/__init__.py +0 -0
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/cli.py +0 -0
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/handlers/__init__.py +0 -0
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/handlers/fallback.py +0 -0
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/handlers/fetch.py +0 -0
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/handlers/repology.py +0 -0
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/handlers/scan.py +0 -0
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/main.py +0 -0
- {sbo_create-2.3.0 → sbo_create-2.3.2}/sbo_create/template_loader.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "flit_core.buildapi"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sbo-create"
|
|
7
|
-
version = "2.3.
|
|
7
|
+
version = "2.3.2"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name = "Dimitris Zlatanidis", email = "dslackw@gmail.com" },
|
|
10
10
|
]
|
|
@@ -35,6 +35,10 @@ dependencies = [
|
|
|
35
35
|
"urllib3>=1.26"
|
|
36
36
|
]
|
|
37
37
|
|
|
38
|
+
[tool.isort]
|
|
39
|
+
profile = "black"
|
|
40
|
+
known_first_party = ["sbo_create"]
|
|
41
|
+
|
|
38
42
|
[tool.mypy]
|
|
39
43
|
strict = true
|
|
40
44
|
warn_return_any = true
|
|
@@ -4,8 +4,7 @@
|
|
|
4
4
|
__prog__: str = 'sbo-create'
|
|
5
5
|
__author__: str = 'dslackw'
|
|
6
6
|
__copyright__: str = '2015-2026'
|
|
7
|
-
|
|
8
|
-
__version__: str = f'{__version_info__[0]}.{__version_info__[1]}.{__version_info__[2]}'
|
|
7
|
+
__version__: str = '2.3.2'
|
|
9
8
|
__license__: str = 'GNU General Public License v3 (GPLv3)'
|
|
10
9
|
__email__: str = 'dslackw@gmail.com'
|
|
11
10
|
__website__: str = 'https://gitlab.com/dslackw/sbo-create'
|
|
@@ -81,8 +81,7 @@ class BumpHandler: # pylint: disable=too-few-public-methods
|
|
|
81
81
|
"""
|
|
82
82
|
if len(values) == 1:
|
|
83
83
|
return f'{label}="{values[0]}"'
|
|
84
|
-
|
|
85
|
-
body: str = f' \\\n{indent}'.join(values)
|
|
84
|
+
body: str = ' \\\n '.join(values)
|
|
86
85
|
return f'{label}="{body}"'
|
|
87
86
|
|
|
88
87
|
def _bump_md5sums(self, content: str) -> tuple[str, bool]:
|
|
@@ -167,7 +167,7 @@ class DownloadHandler:
|
|
|
167
167
|
def download(self, link: str) -> bool:
|
|
168
168
|
"""Download a single source file using wget into the current folder.
|
|
169
169
|
|
|
170
|
-
Runs wget with
|
|
170
|
+
Runs wget with -N so partial downloads are replace. stdout and
|
|
171
171
|
stderr are suppressed to keep terminal output clean.
|
|
172
172
|
|
|
173
173
|
Args:
|
|
@@ -177,6 +177,6 @@ class DownloadHandler:
|
|
|
177
177
|
True if wget exited with return code 0, False otherwise.
|
|
178
178
|
"""
|
|
179
179
|
rc: int = subprocess.run(
|
|
180
|
-
['wget', '
|
|
180
|
+
['wget', '-N', link], check=False,
|
|
181
181
|
stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL).returncode
|
|
182
182
|
return rc == 0
|
|
@@ -9,8 +9,15 @@ import sys
|
|
|
9
9
|
from collections.abc import Callable
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
|
|
12
|
-
from sbo_create.models import (
|
|
13
|
-
|
|
12
|
+
from sbo_create.models import (
|
|
13
|
+
PROG,
|
|
14
|
+
AppContext,
|
|
15
|
+
colorize,
|
|
16
|
+
confirm,
|
|
17
|
+
select_option,
|
|
18
|
+
set_arm_labels,
|
|
19
|
+
set_x86_labels,
|
|
20
|
+
)
|
|
14
21
|
from sbo_create.template_loader import TemplateLoader
|
|
15
22
|
|
|
16
23
|
|
|
@@ -8,8 +8,13 @@ import re
|
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
|
|
10
10
|
from sbo_create.handlers.files import FileHandler
|
|
11
|
-
from sbo_create.models import (
|
|
12
|
-
|
|
11
|
+
from sbo_create.models import (
|
|
12
|
+
SOURCE_EXTENSIONS,
|
|
13
|
+
UNSUPPORTED,
|
|
14
|
+
AppContext,
|
|
15
|
+
colorize,
|
|
16
|
+
confirm,
|
|
17
|
+
)
|
|
13
18
|
|
|
14
19
|
|
|
15
20
|
class FixHandler: # pylint: disable=too-few-public-methods
|
|
@@ -27,11 +32,13 @@ class FixHandler: # pylint: disable=too-few-public-methods
|
|
|
27
32
|
"""Auto-fix trailing whitespace in a file, optionally fixing the final newline.
|
|
28
33
|
|
|
29
34
|
Strips trailing whitespace from each line while preserving backslash
|
|
30
|
-
continuations. Optionally ensures the file ends with
|
|
35
|
+
continuations. Optionally ensures the file ends with exactly one newline,
|
|
36
|
+
stripping any extra trailing blank lines (for README).
|
|
31
37
|
|
|
32
38
|
Args:
|
|
33
39
|
filepath: Path to the file to fix.
|
|
34
|
-
fix_newline: If True, ensure the file ends with '\\n
|
|
40
|
+
fix_newline: If True, ensure the file ends with exactly '\\n' (strips
|
|
41
|
+
extra trailing blank lines).
|
|
35
42
|
|
|
36
43
|
Returns:
|
|
37
44
|
A tuple of (ws_fixed, newline_fixed) — True for each fix that was applied.
|
|
@@ -57,9 +64,10 @@ class FixHandler: # pylint: disable=too-few-public-methods
|
|
|
57
64
|
|
|
58
65
|
newline_fixed: bool = False
|
|
59
66
|
if fix_newline:
|
|
60
|
-
|
|
67
|
+
correct: str = content.rstrip('\n') + '\n'
|
|
68
|
+
newline_fixed = content != correct
|
|
61
69
|
if newline_fixed:
|
|
62
|
-
content =
|
|
70
|
+
content = correct
|
|
63
71
|
|
|
64
72
|
if ws_fixed or newline_fixed:
|
|
65
73
|
filepath.write_text(content, encoding='utf-8')
|
|
@@ -418,10 +426,10 @@ class FixHandler: # pylint: disable=too-few-public-methods
|
|
|
418
426
|
)
|
|
419
427
|
if not tarballs:
|
|
420
428
|
return False
|
|
421
|
-
print("Source tarballs to remove:\n")
|
|
429
|
+
print(f"Source tarballs to remove ({len(tarballs)}):\n")
|
|
422
430
|
for f in tarballs:
|
|
423
431
|
print(f" {f.name}")
|
|
424
|
-
if not confirm("Remove?", before_newline=True, after_newline=
|
|
432
|
+
if not confirm(f"Remove {colorize(str(len(tarballs)), 'red')} file(s)?", before_newline=True, after_newline=True):
|
|
425
433
|
return False
|
|
426
434
|
for f in tarballs:
|
|
427
435
|
f.unlink()
|
|
@@ -443,10 +451,10 @@ class FixHandler: # pylint: disable=too-few-public-methods
|
|
|
443
451
|
name: str = self.ctx.prg_name
|
|
444
452
|
folder: Path = self.ctx.current_folder
|
|
445
453
|
candidates: list[tuple[str, bool]] = [
|
|
446
|
-
(f'{name}.info',
|
|
454
|
+
(f'{name}.info', True),
|
|
447
455
|
('README', True),
|
|
448
|
-
(f'{name}.SlackBuild',
|
|
449
|
-
('slack-desc',
|
|
456
|
+
(f'{name}.SlackBuild', True),
|
|
457
|
+
('slack-desc', True),
|
|
450
458
|
]
|
|
451
459
|
width: int = max(
|
|
452
460
|
(len(filename)
|
|
@@ -234,8 +234,15 @@ class GitHandler:
|
|
|
234
234
|
|
|
235
235
|
entries: list[tuple[str, str]] = []
|
|
236
236
|
for subject in subjects:
|
|
237
|
-
m = re.match(r'^(\S+/\S+):\s+.*?(\
|
|
238
|
-
|
|
237
|
+
m = re.match(r'^(\S+/\S+):\s+.*?[Vv]ersion\s+(\S+?)\.?\s*$', subject)
|
|
238
|
+
if m:
|
|
239
|
+
entries.append((m.group(1), m.group(2)))
|
|
240
|
+
else:
|
|
241
|
+
pkg_m = re.match(r'^(\S+/\S+):\s*(.*)', subject)
|
|
242
|
+
if pkg_m:
|
|
243
|
+
entries.append((pkg_m.group(1), pkg_m.group(2).rstrip('.')))
|
|
244
|
+
else:
|
|
245
|
+
entries.append((subject, ''))
|
|
239
246
|
|
|
240
247
|
print(f"Commits on {colorize(branch, 'cyan')} (since {main}):\n")
|
|
241
248
|
for pkg, ver in entries:
|
|
@@ -17,8 +17,14 @@ from urllib3.exceptions import HTTPError # pylint: disable=import-error
|
|
|
17
17
|
from sbo_create.handlers.fallback import SboResolver
|
|
18
18
|
from sbo_create.handlers.files import FileHandler
|
|
19
19
|
from sbo_create.handlers.validate import ValidateHandler
|
|
20
|
-
from sbo_create.models import (
|
|
21
|
-
|
|
20
|
+
from sbo_create.models import (
|
|
21
|
+
EMAIL_RE,
|
|
22
|
+
PROG,
|
|
23
|
+
SOURCE_EXTENSIONS,
|
|
24
|
+
AppContext,
|
|
25
|
+
colorize,
|
|
26
|
+
confirm,
|
|
27
|
+
)
|
|
22
28
|
|
|
23
29
|
|
|
24
30
|
def _print_tree_branch( # pylint: disable=too-many-arguments,too-many-positional-arguments
|
|
@@ -433,7 +439,7 @@ class MiscHandler:
|
|
|
433
439
|
raise SystemExit(1) from exc
|
|
434
440
|
raise SystemExit(0)
|
|
435
441
|
|
|
436
|
-
def _diff_files(self, sbo_pkg_path: Path, local_path: Path, context: int) -> bool: # pylint: disable=too-many-locals
|
|
442
|
+
def _diff_files(self, sbo_pkg_path: Path, local_path: Path, context: int) -> bool: # pylint: disable=[too-many-locals, too-many-branches]
|
|
437
443
|
"""Compute and print a unified diff between SBo repo files and local files.
|
|
438
444
|
|
|
439
445
|
Args:
|
|
@@ -444,9 +450,21 @@ class MiscHandler:
|
|
|
444
450
|
Returns:
|
|
445
451
|
True if at least one file had differences, False otherwise.
|
|
446
452
|
"""
|
|
453
|
+
try:
|
|
454
|
+
repo_files: set[str] = {f.name for f in sbo_pkg_path.iterdir() if f.is_file()}
|
|
455
|
+
local_files: set[str] = {f.name for f in local_path.iterdir() if f.is_file()}
|
|
456
|
+
except FileNotFoundError as err:
|
|
457
|
+
if not sbo_pkg_path.is_dir():
|
|
458
|
+
print(colorize(f"Error: SBo repository path not found: '{sbo_pkg_path}'", "red"))
|
|
459
|
+
elif not local_path.is_dir():
|
|
460
|
+
print(colorize(f"Error: Local package path not found: '{local_path}'", "red"))
|
|
461
|
+
else:
|
|
462
|
+
print(colorize(f"Error: Path not found: '{err.filename}'", "red"))
|
|
463
|
+
return False
|
|
464
|
+
|
|
447
465
|
any_diff: bool = False
|
|
448
466
|
skipped: list[str] = []
|
|
449
|
-
for filename in sorted(
|
|
467
|
+
for filename in sorted(repo_files):
|
|
450
468
|
if filename.endswith(SOURCE_EXTENSIONS):
|
|
451
469
|
if (local_path / filename).is_file():
|
|
452
470
|
skipped.append(filename)
|
|
@@ -476,8 +494,9 @@ class MiscHandler:
|
|
|
476
494
|
for src in skipped:
|
|
477
495
|
print(src)
|
|
478
496
|
|
|
479
|
-
repo_files: set[str] = {f.name for f in sbo_pkg_path.iterdir() if f.is_file()}
|
|
480
|
-
local_files: set[str] = {f.name for f in local_path.iterdir() if f.is_file()}
|
|
497
|
+
# repo_files: set[str] = {f.name for f in sbo_pkg_path.iterdir() if f.is_file()}
|
|
498
|
+
# local_files: set[str] = {f.name for f in local_path.iterdir() if f.is_file()}
|
|
499
|
+
|
|
481
500
|
new_files: list[str] = sorted(local_files - repo_files)
|
|
482
501
|
if new_files:
|
|
483
502
|
print("\nNew in local (not in SBo repo):")
|
|
@@ -516,8 +535,12 @@ class MiscHandler:
|
|
|
516
535
|
if not sbo_pkg_path.is_dir():
|
|
517
536
|
print(colorize(f"{PROG}: '{category}/{name}' not found in repo.", 'red'))
|
|
518
537
|
continue
|
|
519
|
-
|
|
520
|
-
|
|
538
|
+
|
|
539
|
+
if from_cwd or self.ctx.current_folder.name == name:
|
|
540
|
+
local_path: Path = self.ctx.current_folder
|
|
541
|
+
else:
|
|
542
|
+
local_path = self.ctx.current_folder / orig_name
|
|
543
|
+
|
|
521
544
|
if sbo_pkg_path.resolve() == local_path.resolve():
|
|
522
545
|
print(colorize(
|
|
523
546
|
f"{PROG}: '{name}' local path and repo path are the same directory.\n"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/python3
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
|
+
# pylint: disable=too-many-lines
|
|
3
4
|
|
|
4
5
|
from __future__ import annotations
|
|
5
6
|
|
|
@@ -12,8 +13,14 @@ import urllib3 # pylint: disable=import-error
|
|
|
12
13
|
from sbo_create.handlers.fallback import SboResolver
|
|
13
14
|
from sbo_create.handlers.files import FileHandler
|
|
14
15
|
from sbo_create.handlers.fix import FixHandler
|
|
15
|
-
from sbo_create.models import (
|
|
16
|
-
|
|
16
|
+
from sbo_create.models import (
|
|
17
|
+
EMAIL_RE,
|
|
18
|
+
PROG,
|
|
19
|
+
SOURCE_EXTENSIONS,
|
|
20
|
+
UNSUPPORTED,
|
|
21
|
+
AppContext,
|
|
22
|
+
colorize,
|
|
23
|
+
)
|
|
17
24
|
|
|
18
25
|
|
|
19
26
|
class ValidateHandler:
|
|
@@ -251,20 +258,46 @@ class ValidateHandler:
|
|
|
251
258
|
errors.append(f"{colorize(filename, 'red')}: required file missing")
|
|
252
259
|
return errors
|
|
253
260
|
|
|
254
|
-
def _check_readme(self) -> list[str]:
|
|
255
|
-
"""Check that README exists
|
|
261
|
+
def _check_readme(self) -> tuple[list[str], list[str]]:
|
|
262
|
+
"""Check that README exists and is not empty.
|
|
256
263
|
|
|
257
264
|
Returns:
|
|
258
|
-
|
|
265
|
+
A tuple of (errors, warnings).
|
|
259
266
|
"""
|
|
260
267
|
errors: list[str] = []
|
|
268
|
+
warnings: list[str] = []
|
|
261
269
|
readme: Path = Path(self.ctx.current_folder, 'README')
|
|
262
270
|
if readme.is_file():
|
|
263
271
|
content: str = readme.read_text(encoding='utf-8')
|
|
264
272
|
if not content.strip():
|
|
265
273
|
errors.append(f"{colorize('README', 'red')}: is empty")
|
|
266
|
-
|
|
267
|
-
|
|
274
|
+
return errors, warnings
|
|
275
|
+
|
|
276
|
+
def _check_trailing_newlines(self) -> list[str]:
|
|
277
|
+
"""Check that no submission file ends with trailing blank lines or missing newline.
|
|
278
|
+
|
|
279
|
+
Checks .info, .SlackBuild, slack-desc and README.
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
List of error message strings (empty if all checks pass).
|
|
283
|
+
"""
|
|
284
|
+
errors: list[str] = []
|
|
285
|
+
name: str = self.ctx.prg_name
|
|
286
|
+
for filename in [f'{name}.info', f'{name}.SlackBuild', 'slack-desc', 'README']:
|
|
287
|
+
path: Path = Path(self.ctx.current_folder, filename)
|
|
288
|
+
if not path.is_file():
|
|
289
|
+
continue
|
|
290
|
+
content: str = path.read_text(encoding='utf-8')
|
|
291
|
+
if not content.strip():
|
|
292
|
+
continue
|
|
293
|
+
if not content.endswith('\n'):
|
|
294
|
+
errors.append(
|
|
295
|
+
f"{colorize(filename, 'red')}: must end with a newline"
|
|
296
|
+
" (run --fix to add)")
|
|
297
|
+
elif content.endswith('\n\n'):
|
|
298
|
+
errors.append(
|
|
299
|
+
f"{colorize(filename, 'red')}: ends with trailing blank line(s)"
|
|
300
|
+
" (run --fix to remove)")
|
|
268
301
|
return errors
|
|
269
302
|
|
|
270
303
|
def _check_no_sources(self) -> list[str]:
|
|
@@ -754,14 +787,16 @@ class ValidateHandler:
|
|
|
754
787
|
info_lines: list[str] = info_file.read_text(encoding='utf-8').splitlines()
|
|
755
788
|
info_var_errors = self._validate_info_variables(info_lines)
|
|
756
789
|
|
|
790
|
+
readme_errors, readme_warnings = self._check_readme()
|
|
757
791
|
md5_errors, warnings = self._check_md5sums(show_warnings)
|
|
792
|
+
warnings = readme_warnings + warnings
|
|
758
793
|
copyright_warn: str = self._check_copyright_year()
|
|
759
794
|
if copyright_warn:
|
|
760
795
|
warnings.append(copyright_warn)
|
|
761
796
|
|
|
762
797
|
groups: list[tuple[str, list[str]]] = [
|
|
763
798
|
('Required files', required_errors),
|
|
764
|
-
('README',
|
|
799
|
+
('README', readme_errors),
|
|
765
800
|
('.info variables', info_var_errors),
|
|
766
801
|
('.info consistency', self._check_info_consistency()),
|
|
767
802
|
('.info quotes', self._check_info_quotes()),
|
|
@@ -769,6 +804,7 @@ class ValidateHandler:
|
|
|
769
804
|
('slack-desc', self._check_slack_desc()),
|
|
770
805
|
('REQUIRES', self._check_requires_existence()),
|
|
771
806
|
('Trailing whitespace', self._check_trailing_whitespace()),
|
|
807
|
+
('Trailing newlines', self._check_trailing_newlines()),
|
|
772
808
|
('ASCII encoding', self._check_ascii()),
|
|
773
809
|
('MD5SUM', md5_errors),
|
|
774
810
|
]
|
|
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
|
|
File without changes
|