mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-02 17:23:56 +08:00
🤞 Sync 2026-09-27 22:16:29
This commit is contained in:
1 parent
8ede4a8320
commit
618f51e9dc
459 files changed
+44817
-2191
No files matched your search
+96
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build a deterministic opkg package without requiring an OpenWrt SDK."""
|
||||
|
||||
import gzip
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
import tarfile
|
||||
|
||||
EPOCH = 0
|
||||
|
||||
|
||||
def normalize(info):
|
||||
info.uid = info.gid = 0
|
||||
info.uname = info.gname = "root"
|
||||
info.mtime = EPOCH
|
||||
return info
|
||||
|
||||
|
||||
def archive(members):
|
||||
raw = io.BytesIO()
|
||||
with tarfile.open(fileobj=raw, mode="w", format=tarfile.GNU_FORMAT) as tar:
|
||||
for archive_name, path in members:
|
||||
info = normalize(tar.gettarinfo(path, archive_name))
|
||||
if info.isreg():
|
||||
with open(path, "rb") as source:
|
||||
tar.addfile(info, source)
|
||||
else:
|
||||
tar.addfile(info)
|
||||
compressed = io.BytesIO()
|
||||
with gzip.GzipFile(fileobj=compressed, mode="wb", mtime=EPOCH) as output:
|
||||
output.write(raw.getvalue())
|
||||
return compressed.getvalue()
|
||||
|
||||
|
||||
def walk_payload(stage):
|
||||
result = []
|
||||
for root, directories, files in os.walk(stage):
|
||||
directories.sort()
|
||||
relative = os.path.relpath(root, stage)
|
||||
if relative == "CONTROL" or relative.startswith("CONTROL" + os.sep):
|
||||
continue
|
||||
if relative != ".":
|
||||
result.append(("./" + relative, root))
|
||||
for name in sorted(files):
|
||||
path = os.path.join(root, name)
|
||||
result.append(("./" + os.path.relpath(path, stage), path))
|
||||
return sorted(result)
|
||||
|
||||
|
||||
def field(path, name):
|
||||
with open(path, encoding="utf-8") as source:
|
||||
for line in source:
|
||||
if line.startswith(name + ":"):
|
||||
return line.split(":", 1)[1].strip()
|
||||
raise SystemExit(f"missing {name} in {path}")
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 3:
|
||||
raise SystemExit("usage: pack-ipk.py STAGE OUTPUT_DIR")
|
||||
stage, output_dir = sys.argv[1:]
|
||||
control_dir = os.path.join(stage, "CONTROL")
|
||||
control_path = os.path.join(control_dir, "control")
|
||||
control_members = [("./", control_dir)]
|
||||
control_members.extend(
|
||||
("./" + name, os.path.join(control_dir, name))
|
||||
for name in sorted(os.listdir(control_dir))
|
||||
)
|
||||
parts = {
|
||||
"debian-binary": b"2.0\n",
|
||||
"control.tar.gz": archive(control_members),
|
||||
"data.tar.gz": archive(walk_payload(stage)),
|
||||
}
|
||||
package = field(control_path, "Package")
|
||||
version = field(control_path, "Version")
|
||||
architecture = field(control_path, "Architecture")
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
output_path = os.path.join(
|
||||
output_dir, f"{package}_{version}_{architecture}.ipk"
|
||||
)
|
||||
raw = io.BytesIO()
|
||||
with tarfile.open(fileobj=raw, mode="w", format=tarfile.GNU_FORMAT) as tar:
|
||||
for name in ("debian-binary", "control.tar.gz", "data.tar.gz"):
|
||||
payload = parts[name]
|
||||
info = normalize(tarfile.TarInfo("./" + name))
|
||||
info.mode = 0o644
|
||||
info.size = len(payload)
|
||||
tar.addfile(info, io.BytesIO(payload))
|
||||
with gzip.GzipFile(output_path, "wb", mtime=EPOCH) as output:
|
||||
output.write(raw.getvalue())
|
||||
print(output_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user