Add MX-T40 BLE desktop controller and protocol documentation
Checks / tests (ubuntu-latest, 3.11) (push) Canceled after 0s
Checks / tests (ubuntu-latest, 3.14) (push) Canceled after 0s
Checks / tests (windows-latest, 3.11) (push) Canceled after 0s
Checks / tests (windows-latest, 3.14) (push) Canceled after 0s
Checks / package (push) Canceled after 0s
Checks / tests (ubuntu-latest, 3.11) (push) Canceled after 0s
Checks / tests (ubuntu-latest, 3.14) (push) Canceled after 0s
Checks / tests (windows-latest, 3.11) (push) Canceled after 0s
Checks / tests (windows-latest, 3.14) (push) Canceled after 0s
Checks / package (push) Canceled after 0s
This commit is contained in:
38 files changed
+2344
No files matched your search
@@ -0,0 +1,83 @@
|
||||
"""Copy an explicit source allowlist into a new repository directory.
|
||||
|
||||
This workspace also holds firmware research. Exporting from an allowlist,
|
||||
rather than recursively copying the workspace and subtracting known inputs,
|
||||
prevents newly added vendor artifacts from silently entering a release.
|
||||
The destination must be empty; existing content is never replaced.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
ROOT_FILES = (
|
||||
"README.md",
|
||||
"CONTRIBUTING.md",
|
||||
"LICENSE",
|
||||
"LICENSE.txt",
|
||||
"pyproject.toml",
|
||||
"uv.lock",
|
||||
"MANIFEST.in",
|
||||
"requirements.txt",
|
||||
"requirements-diagnostics.txt",
|
||||
".gitignore",
|
||||
)
|
||||
TREES = {
|
||||
"controller": {".py"},
|
||||
"tests": {".py"},
|
||||
"docs": {".md"},
|
||||
"scripts": {".py"},
|
||||
".github": {".yml", ".yaml"},
|
||||
}
|
||||
|
||||
|
||||
def source_files(root):
|
||||
root = Path(root).resolve()
|
||||
selected = [root / name for name in ROOT_FILES if (root / name).is_file()]
|
||||
for folder, suffixes in TREES.items():
|
||||
selected.extend(
|
||||
path
|
||||
for path in (root / folder).rglob("*")
|
||||
if path.is_file() and path.suffix in suffixes and "__pycache__" not in path.parts
|
||||
)
|
||||
for path in selected:
|
||||
if path.is_symlink() or not path.resolve().is_relative_to(root):
|
||||
raise ValueError(
|
||||
f"Export refuses symlinked or external source: {path.relative_to(root)}"
|
||||
)
|
||||
return sorted(selected)
|
||||
|
||||
|
||||
def export_project(root, destination):
|
||||
root = Path(root).resolve()
|
||||
destination = Path(destination)
|
||||
if destination.is_symlink():
|
||||
raise ValueError("Export destination cannot be a symlink")
|
||||
destination = destination.resolve()
|
||||
if destination == root or any(destination.is_relative_to(root / folder) for folder in TREES):
|
||||
raise ValueError("Choose a destination outside the included source folders")
|
||||
if destination.exists() and (not destination.is_dir() or any(destination.iterdir())):
|
||||
raise ValueError("Export destination must be a new or empty directory")
|
||||
files = source_files(root)
|
||||
destination.mkdir(parents=True, exist_ok=True)
|
||||
for source in files:
|
||||
target = destination / source.relative_to(root)
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy2(source, target)
|
||||
return len(files)
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("destination", type=Path)
|
||||
args = parser.parse_args()
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
try:
|
||||
count = export_project(root, args.destination)
|
||||
except ValueError as exc:
|
||||
parser.error(str(exc))
|
||||
print(f"Exported {count} source/documentation files to {args.destination}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user