| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- import os
- import sys
- import plistlib
- import glob
- import subprocess
- import argparse
- import requests
- import xmltodict
- def download_build(url):
- print(f'Downloading build "{url}"...')
- filename = url.rpartition("/")[2]
- r = requests.get(url)
- if r.status_code == 200:
- with open(f"artifacts/{filename}", "wb") as f:
- f.write(r.content)
- else:
- print(f"Build download failed, status code: {r.status_code}")
- sys.exit(1)
- def read_appcast(url):
- print(f"Downloading feed {url} ...")
- r = requests.get(url)
- if r.status_code != 200:
- print(f"Appcast download failed, status code: {r.status_code}")
- sys.exit(1)
- filename = url.rpartition("/")[2]
- with open(f"builds/{filename}", "wb") as f:
- f.write(r.content)
- appcast = xmltodict.parse(r.content, force_list=("item",))
- dl = 0
- for item in appcast["rss"]["channel"]["item"]:
- channel = item.get("sparkle:channel", "stable")
- if channel != target_branch:
- continue
- if dl == max_old_vers:
- break
- download_build(item["enclosure"]["@url"])
- dl += 1
- def get_appcast_url(artifact_dir):
- dmgs = glob.glob(artifact_dir + "/*.dmg")
- if not dmgs:
- raise ValueError("No artifacts!")
- elif len(dmgs) > 1:
- raise ValueError("Too many artifacts!")
- dmg = dmgs[0]
- print(f"Mounting {dmg} ...")
- out = subprocess.check_output(
- [
- "hdiutil",
- "attach",
- "-readonly",
- "-noverify",
- "-noautoopen",
- "-plist",
- dmg,
- ]
- )
- d = plistlib.loads(out)
- mountpoint = ""
- for item in d["system-entities"]:
- if "mount-point" not in item:
- continue
- mountpoint = item["mount-point"]
- break
- url = None
- plist_files = glob.glob(mountpoint + "/*.app/Contents/Info.plist")
- if plist_files:
- plist_file = plist_files[0]
- print(f"Reading plist {plist_file} ...")
- plist = plistlib.load(open(plist_file, "rb"))
- url = plist.get("SUFeedURL", None)
- else:
- print("No Plist file found!")
- print(f"Unmounting {mountpoint}")
- subprocess.check_call(["hdiutil", "detach", mountpoint])
- return url
- if __name__ == "__main__":
- parser = argparse.ArgumentParser()
- parser.add_argument(
- "--artifacts-dir",
- dest="artifacts",
- action="store",
- default="artifacts",
- help="Folder containing artifact",
- )
- parser.add_argument(
- "--branch",
- dest="branch",
- action="store",
- default="stable",
- help="Channel/Branch",
- )
- parser.add_argument(
- "--max-old-versions",
- dest="max_old_ver",
- action="store",
- type=int,
- default=1,
- help="Maximum old versions to download",
- )
- args = parser.parse_args()
- target_branch = args.branch
- max_old_vers = args.max_old_ver
- url = get_appcast_url(args.artifacts)
- if not url:
- raise ValueError("Failed to get Sparkle URL from DMG!")
- read_appcast(url)
|