mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-10-15 00:09:39 +08:00
96 lines
4.0 KiB
Python
96 lines
4.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Record the source corresponding to an iOS build without changing the checkout."""
|
|
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import subprocess
|
|
import sys
|
|
from urllib.parse import quote
|
|
|
|
REPO = Path(__file__).resolve().parents[3]
|
|
REPOSITORY_URL = "https://github.com/kunkundi/crossdesk"
|
|
MINIRTC_URL = "https://github.com/kunkundi/minirtc"
|
|
|
|
|
|
def git(*args, root=REPO):
|
|
return subprocess.check_output(["git", "-C", str(root), *args], text=True).strip()
|
|
|
|
|
|
def component_sources(lock, mini_revision):
|
|
"""Resolve MiniRTC source and recipe links without rewriting reviewed notices."""
|
|
mini_url = f"{MINIRTC_URL}/tree/{mini_revision}"
|
|
sources = {}
|
|
for component in lock["components"]:
|
|
source = component["source"]
|
|
entry = {}
|
|
if source["kind"] == "repository" and source["url"] == MINIRTC_URL:
|
|
entry.update(version=mini_revision, sourceURL=mini_url)
|
|
recipe = component.get("recipe_path", "")
|
|
if recipe.startswith("deps/submodules/minirtc/"):
|
|
directory = Path(recipe).relative_to("deps/submodules/minirtc").parent
|
|
entry["buildSourceURL"] = f"{mini_url}/{directory.as_posix()}"
|
|
if entry:
|
|
sources[component["id"]] = entry
|
|
return sources
|
|
|
|
|
|
def source_metadata(require_release=False, tag=None):
|
|
revision = git("rev-parse", "HEAD")
|
|
dirty = bool(git("status", "--porcelain", "--untracked-files=normal", "--ignore-submodules=none"))
|
|
tags = git("tag", "--points-at", "HEAD").splitlines()
|
|
if tag:
|
|
if tag not in tags:
|
|
raise ValueError(f"Source tag {tag!r} does not point to the build commit")
|
|
else:
|
|
# 'latest' is a moving alias, never a corresponding-source identifier.
|
|
versions = sorted(t for t in tags if t.startswith("v"))
|
|
tag = versions[0] if versions else None
|
|
if require_release and (dirty or not tag or not tag.startswith("v")):
|
|
raise ValueError("Release source must be a clean checkout of a version tag, with matching submodules")
|
|
mini_revision = git("rev-parse", "HEAD", root=REPO / "deps/submodules/minirtc")
|
|
lock_path = REPO / "apps/ios/licenses/sources.json"
|
|
lock = json.loads(lock_path.read_text())
|
|
ref = quote(tag if tag and not dirty else revision, safe="")
|
|
return {
|
|
"schemaVersion": 1,
|
|
"repositoryURL": REPOSITORY_URL,
|
|
"revision": revision,
|
|
"tag": tag,
|
|
"isModified": dirty,
|
|
"sourceURL": f"{REPOSITORY_URL}/tree/{ref}",
|
|
"buildInstructionsURL": f"{REPOSITORY_URL}/blob/{ref}/apps/ios/README.md",
|
|
"privacyPolicyURL": f"{REPOSITORY_URL}/blob/{ref}/PRIVACY.md",
|
|
"miniRTCRevision": mini_revision,
|
|
"miniRTCSourceURL": f"{MINIRTC_URL}/tree/{mini_revision}",
|
|
"componentSources": component_sources(lock, mini_revision),
|
|
"licenseCatalogSHA256": lock["bundle_sha256"],
|
|
"sourceCatalogSHA256": hashlib.sha256(lock_path.read_bytes()).hexdigest(),
|
|
"toolchain": lock["toolchain"],
|
|
}
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--output", required=True, type=Path)
|
|
parser.add_argument("--tag", default=os.environ.get("CROSSDESK_SOURCE_TAG") or None)
|
|
parser.add_argument("--require-release", action="store_true",
|
|
default=os.environ.get("CROSSDESK_RELEASE_BUILD") == "YES")
|
|
args = parser.parse_args()
|
|
metadata = source_metadata(args.require_release, args.tag)
|
|
data = (json.dumps(metadata, ensure_ascii=False, indent=2) + "\n").encode()
|
|
args.output.parent.mkdir(parents=True, exist_ok=True)
|
|
if not args.output.exists() or args.output.read_bytes() != data:
|
|
args.output.write_bytes(data)
|
|
print(f"Recorded iOS source: {metadata['revision']} (modified: {metadata['isModified']})")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
main()
|
|
except (OSError, ValueError, subprocess.CalledProcessError) as error:
|
|
print(f"iOS source metadata: {error}", file=sys.stderr)
|
|
sys.exit(1)
|